为什么sed会与群组外的某些内容相匹配?

时间:2017-02-09 03:48:03

标签: linux bash unix sed terminal

我最近尝试使用sed从逗号和换行符分隔的枚举成员生成一堆方法。我遇到了以下似乎不直观的行为:

$ echo 'Hello,' | sed 's/\(.*\),\?/"Hi \1!"/g'
"Hi Hello,!"

在这里,我尝试通过\(.*\)将逗号之前的所有内容捕获到一个组中,然后我允许使用,\?的可选逗号。我希望这可以用第一个逗号之前的所有内容替换\1,即Hello,但由于某种原因,逗号也被包含在替换中,尽管它不在组内。为什么会这样?

2 个答案:

答案 0 :(得分:1)

正则表达式默认执行贪婪匹配(从左到右),如果最贪婪的匹配不起作用则回溯。因此,对于\(.*\),\?,最贪婪的匹配是将Hello,\(.*\)匹配,而不是,\?

我不确定如何在基本正则表达式中进行非贪婪匹配(这是sed使用的)。在Perl风格的正则表达式(sed未使用)中,您在匹配运算符后面添加了一个问号,因此您使用(.*?),?之类的内容。

您可以做的第二件事就是使用类似\([^,]*\),\?的内容,但它会在它看到的第一个逗号处停止匹配。

答案 1 :(得分:1)

那是因为sed正则表达式是贪婪的,而?量词表示匹配前一个标记的0或1 - 在这种情况下为,

所以,这里引擎贪婪地匹配到最后,并且??设为可选的,它也被包含在捕获的组(.*)中。

要获得所需的行为,请删除?

%  echo 'Hello,' | sed 's/\(.*\),\?/"Hi \1!"/g'
"Hi Hello,!"

%  echo 'Hello,' | sed 's/\(.*\),/"Hi \1!"/g' 
"Hi Hello!"