为什么 sed/awk 没有按照我的正则表达式所说的那样捕获组?

Why isn't sed/awk capturing groups the way my regex says it should?

我这里有一个根据网站工作的正则表达式:

https://regex101.com/r/doj4We/1

正则表达式:<<act ("([^"\]|\.)*")

正文:

<<act "want" "don't want">><</act>>

<<act "\"want\"" "don't want">><</act>>

第 1 组应该分别捕获“想要”和“\”想要\”,根据网站,确实如此。

但是如果我把这个文本保存在一个文件中,然后执行这个命令:

cat tmp | sed -Ern 's/<<act ("([^"\]|\.)*")//p'

这是输出:

"want" "don't want">><</act>>
"\"want\"" "don't want">><</act>>

为什么 sed 的行为与本网站所说的不同?当我尝试像这样使用 awk 的 gensub 时,我注意到了同样的问题:

cat tmp | awk '{ r = gensub(/<<act ("([^"\]|\.)*")/, "\1", "g"); print r;}' 

为了它的价值,我正在使用 cygwin。

您正在使用 seds 替换命令,因此您正在 搜索和替换 找到的匹配项。您想要获得组 1 的值,因此您需要匹配捕获组之前和 之后 的部分以删除它们以保留您想要的内容。

您可以使用

sed -En 's/<<act ("([^"\]|\.)*").*//p'
#                                ^^

.* 将匹配任何文本并将被删除。这也意味着您只能在字符串的开头使用 <<act 。另请注意,由于括号表达式不支持正则表达式转义,因此 [^"\] 就足够了,无需双重转义 \.

关于选项的注释:-E 启用 POSIX ERE 正则表达式语法,n 抑制默认行输出,p 打印替换结果。

您的正则表达式 <<act ("([^"\]|\.)*") 可以按原样awk 一起使用。此外,如果您使用 gnu-awk 那么您实际上也不需要进行任何替换。它可以在单个 match 函数中完成,如下所示:

awk 'match([=10=], /<<act ("([^"\]|\.)*")/, m) { print m[1] }' file
"want"
"\"want\""

对于 POSIX awk 你可以使用这个 awk:

/awk ' == "<<act" &&  ~ /"([^"\]|\.)*"/{ print  }' file