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



我在这里有一个正则表达式,它根据站点工作:

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

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

text:

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

组1应该捕获";想要";以及"\"想要"&";,根据该网站的说法,确实如此。

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

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

这是输出:

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

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

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

就其价值而言,我正在使用cygwin。

您将sedssubstitution命令一起使用,因此将搜索并替换找到的匹配项。您想要获得组1的值,因此您需要匹配捕获组之前的零件和之后的,以删除它们以保持您想要的。

你可以使用

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

.*将匹配任何文本,并将被删除。这也意味着在字符串的开头只能有<<act。还要注意,由于括号表达式不支持正则表达式转义,[^"]就足够了,不需要对进行双转义。

注意选项:-E启用POSIX ERE regex语法,n抑制默认行输出,p打印替换结果。

您的正则表达式<<act ("([^"\]|\.)*")awk将按原样运行。更重要的是,如果你使用gnu-awk,那么你真的不需要做任何替换。它可以在单个match函数中完成,如下所示:

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

对于POSIX awk,您可以使用此awk:

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

相关内容

最新更新