搜索模式中的Vim / sed正则表达式反向引用

时间:2016-09-08 00:43:21

标签: regex vim sed backreference capturing-group

Vim帮助说:

curl -s -D headers.txt -o out.dat "http://server.com/somefile[00-31].mp4"
httpStatus=$(head -1 headers.txt | awk '{print $2}')
contentType=$(grep "Content-Type:" headers.txt | tr -d '\r')
contentType=${contentType#*: }
if [ "$httpStatus" != "200" ]; then
    echo "FAILED - HTTP STATUS $httpStatus"
else
    echo "SAVED"
fi

看起来反向引用可以在搜索模式中使用。我开始玩它,我注意到我无法解释的行为。这是我的档案:

\1      Matches the same string that was matched by     */\1* *E65*
        the first sub-expression in \( and \). {not in Vi}
        Example: "\([a-z]\).\1" matches "ata", "ehe", "tot", etc. 

我想匹配开始和结束标签匹配的行,即:

<paper-input label="Input label"> Some text </paper-input>
<paper-input label="Input label"> Some text </paper-inputa>
<aza> Some text </az>
<az> Some text </az>
<az> Some text </aza>

我的测试正则表达式是:

<paper-input label="Input label"> Some text </paper-input>
<az> Some text </az>

但这匹配行:%s,<\([^ >]\+\).*<\/\1>,,gn 13 sed

也是如此
4

这个:$ sed -ne 's,<\([^ >]\+\).*<\/\1>,\0,p' file <paper-input label="Input label"> Some text </paper-input> <aza> Some text </az> <az> Some text </az> 应该是贪婪的,当尝试匹配它而不是<\([^ >]\+\)时,所有组都是正确的。但是当我添加\1时,似乎\1变得不贪婪,并且它会尝试强制第3行中的匹配。有人可以解释为什么它匹配<\([^ >]\+\)行:

3rd

这也是regex101 demo

注意 这不是关于正则表达式本身(可能还有其他方法),而是关于该正则表达式的行为。

3 个答案:

答案 0 :(得分:3)

要理解你的正则表达式的行为方式,你需要了解回溯正则表达式引擎的作用。

引擎将贪婪地匹配并消耗尽可能多的字符。但如果找不到匹配,它会返回并尝试找到仍然满足模式的不同匹配。

%s,<\([^ >]\+\).*<\/\1>,,gn

对于第三行<aza> Some text </az>

正则表达式引擎查看\1 = aza。并查看.*</aza>是否与字符串的其余部分匹配。它不会为\1选择其他内容。下次选择\1 = az并查看.*</az>是否与字符串的其余部分匹配时,它会发生。所以字符串匹配

(这是一个简化版本。我跳过了.*本身可能会进行大量回溯的事实。

解决它就像在正则表达式中添加锚一样容易阻止正则表达式搜索其他可能满足\1的值。在这种情况下,匹配空格或>就足够了。

答案 1 :(得分:2)

您需要添加\>来表示单词的结尾。可能有其他解决方案具有0宽度模式,但它会使事情变得复杂。

此外,您的分隔符为,,而不是/

给出了:

%s,<\([^ >]\+\)\>.*</\1>,,gn

答案 2 :(得分:0)

目前,第3行(<aza>)显示为匹配的原因是正则表达式中的.*字词可以跨多行匹配。因此第3行匹配,因为第5行具有结束标记。要更正此问题,请强制正则表达式仅在相同的行上找到匹配的结束标记:

%s,<\([^ >]\+\)[^\n]*?<\/\1>,,gn
               ^^^^^ use [^\n]* instead of .*