如何突出显示所有内线词重复?

时间:2014-06-25 14:14:21

标签: regex vim

我有这个纯文本文件:

1 : Foo Bar Bar Baz
2 : The dog The cat the hamster
3 : the dog the cat the hamster
4 : The dog the cat the hamster The Doors

我想强调所有重复的词语。

我修改了这个解决方案:

/\(\<\w\+\>\)\zs[ w]\+\1

这适用于第一行(第二个栏突出显示)但这不能解决以下问题:

第2行:它突出显示第二个&#34;&#34;,但不是小写&#34;&#34;

第3行:它只突出显示&#34;&#34;

的第一次重复

第4行:它只突出显示第二个&#34;&#34; (第一个重复的单词),但不是第二个&#34;&#34; (另一个重复的词)

PS:只是为了它,一个侧面问题:是否有可能突出显示相邻行中的重复单词,以便在3行的范围内看到相同单词的重复?

提前谢谢

2 个答案:

答案 0 :(得分:3)

效果稍好一点:

/\(\<\w\+\>\).\{-}\zs\<\1\>

的变化:

  • [ w]\+替换为.\{-}(在这对词之间匹配任何字符;非贪婪量词)。
  • 向前移动\zs
  • \1围绕\<...\>;这些锚点自动从捕获子模式继承。

不幸的是,还有一个问题;第三个&#34;&#34;第3行和第2行&#34;&#34;由于与另一场比赛重叠,第4行不匹配。这可以通过使用后视模式\@<=(可能会降低性能)而不是\zs来解决:

/\%(\<\1\>.\+\)\@<=\(\<\w\+\>\)

让这个工作是一个试验和错误;它需要:

  • 在后视模式中使用捕获子模式(即使用\%(...\)代替\(...\)
  • 在后视模式中使用非贪婪量词(即返回OP \+而不是{-}

以下两种模式均可使用以下可选添加项:

  • \c添加到模式中以防止不区分大小写。
  • .替换为\_.,以便在换行符中找到重复字词。

请注意第二种模式,跨线匹配的范围有限。后视搜索只能向后搜索一行。这是设计使然,以避免严重的性能问题。因此,只有当两个单词在同一行上时,或者在紧随其后的行上才会识别出重复的单词。


如果我们按照Qeole的例子来匹配第一个单词而不是最后一个单词,事情会变得更容易;我们可以使用前瞻,它没有与后视相关的大多数缺点。这是完整的,不区分大小写和跨行匹配:

/\<\(\w\+\)\>\(\_.\+\<\1\>\)\@=\c

我们甚至可以将这两种模式与\|结合起来,将两者包含在搜索结果中的第一个和最后一个单词中:

/\%(\<\1\>\_.\+\)\@<=\(\<\w\+\>\)\|\<\(\w\+\)\>\(\_.\+\<\1\>\)\@=\c

Peter Rincker的重要提示:由于NFA正则表达式引擎中的错误,lookbehind在某些​​版本的VIM 7.4中可能无效。您可以强制它使用旧的回溯引擎,并通过预先添加模式\%#=1来获得所需的结果。有关详细信息,请参阅:h NFA。不要在VIM 7.3及更早版本中使用。

/\%#=1\%(\<\1\>\_.\+\)\@<=\(\<\w\+\>\)\|\<\(\w\+\)\>\(\_.\+\<\1\>\)\@=\c

答案 1 :(得分:1)

免责声明:这是一个近似的答案,收集我在@ Ruud的答案和OP的问题的评论中所写的内容。

首先,这是解决案例问题的快速解决方法(Thethe):

:set ignorecase

但是Ruud建议使用\c可能会更好。

然后,这里有一个关于重复单词的出现,包括第一次出现在线,但排除最后一个的提议:

/\(\<\w\+\>\)\ze.\{-}\1

这与Ruud的解决方案非常相似(即使我自己得到它)。如果有人对最后一次出现的修复有兴趣,我有兴趣学习它。


由于Ruud - 再次 - 也指出,一种解决方案可能是使用Vim \@<=。这个\@<=正则表达式原子的文档中有一个有趣的例子:

/\1\@<=,\([a-z]\+\)

应与,abc中的abc,abc匹配,但我无法使此示例正常工作(在我看来\1仍为空)。

我不知道附带问题,对不起。