Regex Vim多行正则表达式提供重叠匹配

Regex Vim多行正则表达式提供重叠匹配,regex,vim,vi,Regex,Vim,Vi,当我注意到我贪婪的多行正则表达式在Vim中提供重叠匹配时,我感到惊讶。正则表达式设计为匹配整个文本块或连续的非空行 正则表达式显然匹配了我期望它匹配的所有内容(突出显示看起来是正确的),但是当使用跳到下一个匹配而不是跳到下一个块时,它转到了当前块中的下一行 下面是我使用的正则表达式(相当于大多数正则表达式引擎的(.+\n){1,}): 这应至少匹配一个非空行,并尽可能多地匹配连续的非空行,下面是一个示例文本文件: block 1 some stuff more stuff block 2 fo

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

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

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

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

block 1
some stuff
more stuff

block 2
foo bar
baz qux
应用这个正则表达式(/\(.\+\n\)\{1,}+Enter)后,两个块会正确高亮显示,但我希望只有两个正则表达式匹配项,每个块对应一个。但是,当我按n键前进到下一个正则表达式匹配时,似乎每个非空行都与正则表达式匹配,因此我的光标将从第一行开始,n将把它移到第二行,然后移到第三行,然后移到块2的开始处,以此类推

如何更改正则表达式,使每个块的预期行为都是单个匹配,从而使n前进到下一个块,而不是下一行?


我还想知道文档中是否有此行为,或者是否有更改此行为的选项。请注意,在搜索/替换中使用相同的正则表达式时,其行为是我所期望的(替换将只应用两次,每个块一次)。

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

\(\%^\|^\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
通过使用该选项,长度可以减少一点:

\v(%^|^\n)\zs(.+\n)+
期待着看到是否有人能想出一个更短的解决方案

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

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

因为你的对手说“匹配一个或多个非空行”,它肯定可以在同一段落中匹配多次。要解决这个问题,您可以指定光标应该放在匹配的末尾,这意味着下一个匹配将从段落的末尾开始。您可以使用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

这允许我跳转到每个块的末尾,这对于正则表达式的简单程度很好,但是如果可能的话,我希望将整个块包含在匹配中。块将包含在匹配中,只是光标将定位在它的末尾。或者你是指其他什么?我所说的“包含在匹配中”是指,如果在搜索/替换中使用相同的正则表达式,则匹配中包含的所有内容都将被替换。另一个等价的意思是“突出显示的文本”。据我所知,
\(\%^\\^\n\)\zs\(.\+\n\)*
完成了同样的事情。但仍然令人沮丧地很长。@NolenRoyalty如果有几行连续的空行,您将匹配一些空行(零宽度匹配),但它确实让我找到了
\(\%^\\\^\n\)\zs\(.\+\n\)\+
,但没有相同的问题。还是挺难看的!
\(.\+\n\)\{1,}\zs