Vim 多行正则表达式给出重叠匹配

Posted

技术标签:

【中文标题】Vim 多行正则表达式给出重叠匹配【英文标题】:Vim multiline regex gives overlapping matches 【发布时间】:2012-04-22 06:04:32 【问题描述】:

当我注意到我的贪婪多行正则表达式在 Vim 中给出重叠匹配时,我感到很惊讶。正则表达式旨在匹配整个文本块或连续的非空行。

正则表达式显然匹配了我期望的所有内容(突出显示看起来正确),但是当使用n 跳到下一个匹配而不是跳到下一个块时,它转到了当前块的下一行。

这是我使用的正则表达式(相当于大多数正则表达式引擎的 (.+\n)1,):

\(.\+\n\)\1,

这应该至少匹配一个非空行,并且尽可能多的连续非空行,这是一个示例文本文件:

block 1
some stuff
more stuff

block 2
foo bar
baz qux

应用此正则表达式后 (/\(.\+\n\)\1,+Enter) 两个块正确突出显示,但我希望正则表达式只有两个匹配项,每个块一个。但是,当我按 n 前进到下一个正则表达式匹配时,似乎每个非空行都与正则表达式匹配,所以我的光标将从第一行开始, n 会把它带到第二行,然后是第三行,然后到块 2 的开头,等等。

如何更改我的正则表达式,以便我看到每个块的预期行为是单个匹配,以便 n 前进到下一个块,而不是下一行?强>

我也有兴趣了解此行为是否在文档中的某处,或者是否有更改此行为的选项。请注意,在搜索/替换中使用相同的正则表达式时,行为是我所期望的(替换只会应用两次,每个块一次)。

【问题讨论】:

【参考方案1】:

以下正则表达式似乎有效:

\(\%^\|^\n\)\zs\(.\+\n\)\+

解释:

\(             # start of group
  \%^          # beginning of file
    \|         # OR
  ^\n          # a blank line
\)             # end of group
\zs            # start matching here
\(.\+\n\)\+    # at least one non-blank line

通过使用very magic 选项,长度可以减少一点:

\v(%^|^\n)\zs(.+\n)+

期待看看是否有人能提出更短的解决方案!

zigdon 的回答帮助我更好地理解了这种行为的原因。当 n 用于跳转到下一个匹配时,它会从光标的当前位置搜索正则表达式的第一个匹配,即使下一个匹配位置包含在上一个匹配中。这就是为什么将正则表达式锚定到块的开头似乎是必要的原因。

感谢 Nolen Royalty 帮助我摆脱了第一组中不必要的前瞻。

【讨论】:

据我所知\(\%^\|^\n\)\zs\(.\+\n\)* 完成了同样的事情。不过,它仍然令人沮丧。 @NolenRoyalty 如果有几个连续的空行,你将匹配一些空行(零宽度匹配),但它确实引导我到\(\%^\|^\n\)\zs\(.\+\n\)\+,它没有同样的问题。还是很丑!【参考方案2】:

由于您的匹配项说“匹配一个或多个非空行”,它当然可以在同一段落中匹配多次。要解决此问题,您可以指定光标应放在匹配的 end 处 - 这意味着下一个匹配将从段落的末尾开始。您可以使用 vim 中的 \zs 零宽度字符来执行此操作:

\zs     Matches at any position, and sets the start of the match there: The
        next char is the first char of the whole match. |/zero-width|

所以你的比赛会变成:

\(.\+\n\)\1,\zs

【讨论】:

这使我可以跳到每个块的末尾,这对于正则表达式的简单性来说是很好的,但如果可能的话,我希望将整个块包含在匹配中。 该块将包含在匹配中,只是光标将定位在它的末尾。还是你的意思是别的? 我所说的“包含在匹配中”的意思是,如果您在搜索/替换中使用相同的正则表达式,则匹配中包含的所有内容都将被替换。另一个等效含义是“突出显示的文本”。

以上是关于Vim 多行正则表达式给出重叠匹配的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式中的重叠匹配

正则表达式如何匹配多行的所有任意字符

Python: 正则表达式匹配多行,实现多行匹配模式

如何使用正则表达式查找重叠匹配?

在 C# 中获取重叠的正则表达式匹配

是否有可能有重叠的正则表达式匹配?