sed 使用关键字、随机单词和已知符号匹配并重新格式化字符串

sed 使用关键字、随机单词和已知符号匹配并重新格式化字符串

经过几个小时的尝试让我的sed查询正常工作后,我即将放弃!

我有以下从源代码中提取的字符串 - 目的是为许多旧的和未记录的代码生成原型。例如:

function foo(bar=1);

我想得到类似的结果:

function foo(
    bar=1)

我想匹配所有以 开头,function后跟随机字母数字(和 - 和 _)单词的行,并添加换行符和制表符sed

我的问题是 sed 默认情况下是贪婪的,由于正则表达式贪婪,我无法sed在第一个换行符之后添加换行符。(

所以像这样的硬编码是有效的:

echo 'function foo(bar=true)' | sed 's:\(function foo(\)\(.*\):\1\n\t\2:g'

这给了我预期的输出:

function foo(
    bar=true)

我可以将其修改为以下内容,在字符后添加换行符(

echo 'function foo(bar=true)' | sed 's:\(function.*(\)\(.*\):\1\n\t\2:g'

这给出了与之前相同的预期结果 - 直到我到达代码中的一个函数,该函数包含一个数组作为参数的默认值 - 这就是贪婪的正则表达式让我困惑的地方:

echo 'function foo(bar=array())' | sed 's:\(function.*(\)\(.*\):\1\n\t\2:g'

这实际上给出了:

function foo(bar=array(
    ))

贪婪导致在后面添加换行符和制表符最后的 (而且不是第一个。不幸的sed不是支持非贪婪正则表达式,这将立即解决所有问题......

所以我尝试制作一个正则表达式来执行如下所示的操作,但我没有得到任何结果:

  • 's:\(function [\w+]\)\(.*\):\1\n\2:g'尝试提取一个字母数字,该数字应该与第一个匹配(
  • 做同样的尝试使用:alnum:类来匹配单词
  • 用更sed友好的方式进行相同的替换[A-Za-z0-9_-],但很难理解如何让它匹配模式中的多个字符,因此它将单词带到第一个(- 然后在第二个返回中获取其余部分。

看来这些字符类在查询中被忽略了,我没有主意了。

由于我无法做到sed非贪婪,因此如何匹配格式为的字符串

KnownKeyword SomethingRandomAlphaNumerical-_(SomethingElse())

转换成一个字符串,在第一个 (, 之后换行后,将如下所示:

KnownKeyword SomethingRandomAlphaNumerical-_(
SomethingElse())

我哪里错了?什么模式可以实现这一目标?

答案1

不要使用点.作为“任何字符”,使用负字符匹配[^(]。所以,你的正则表达式将是:

$ echo 'function foo(bar=array())' | sed 's:\(function[^(]*(\)\(.*\):\1\n\t\2:g'

function foo(
    bar=array())

负匹配将匹配除了首字母后括号内的字符^(换行符除外)之外的任何字符。这意味着 a[^(]可以理解为匹配“not (”。然后还有一个 an*表示尽可能多地重复,它仍然是贪婪的,但不会匹配 a (。简而言之:它将匹配每个字符直到下一个(。这种技术是.*通过赋予限制性特征来限制贪婪。

答案2

匹配以 function 开头的行,子第一个左括号,使用 GNU 添加新行和制表符sed

$ sed '/^function/s/(/&\n\t/' input_file
function foo(
    bar=array())

答案3

为了精确满足您的要求,函数标识符[1]是(字母数字或下划线或连字符)字符:

sed -E 's:function[[:blank:]]+[[:alnum:]_-]+\(:&\n\t:' file`

不需要捕获任何内容,只需将“function”匹配到左括号,然后使用&来引用替换字符串中的匹配文本。

[1] 尽管许多语言限制标识符:第一个字符仅限于字母或下划线。

相关内容