经过几个小时的尝试让我的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] 尽管许多语言限制标识符:第一个字符仅限于字母或下划线。