Vim / sed regex backreference in search pattern

非 Y 不嫁゛ 提交于 2019-12-05 20:23:59

To understand why your regex behaves the way it does you need to understand what a backtracking regex engine does.

The engine will greedily match and consume as many characters as it can. But if it doesn't find a match it goes back and tries to find a different match that still satisfies the pattern.

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

For line three <aza> Some text </az>,

The regex engine looks at \1 = aza. and sees if .*</aza> matches the rest of the string. It doesn't so it chooses something else for \1. The next time it chooses \1 = az and sees if .*</az> matches the rest of the string and it does. So the string matches

(This is a simplified version. I skipped over the fact that .* can potentially do a lot of backtracking itself)


Solving it is as easy as adding an anchor in the regex stops the regex from searching for other values that could satisfy \1. In this case matching a space or > is sufficient.

You need to add \> to indicate end of word. There may be other solutions with 0-width patterns, but it'll complicates things.

Also, your separator is ,, not /

Which gives:

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

Currently the reason why line 3 (<aza>) is showing up as a match is that the .* term in your regex can match across multiple lines. So line 3 matches because line 5 has the closing tag. To correct this, force the regex to find a matching closing tag on the same line only:

%s,<\([^ >]\+\)[^\n]*?<\/\1>,,gn
               ^^^^^ use [^\n]* instead of .*
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!