Vim正则表达式:如何搜索A和B但不包含C

62

我有很多包含美国总统卡特、布什、克林顿和奥巴马名字的行。有些行包含其中一个名字,有些包含两个名字,有些包含三个名字,有些包含所有四个名字(任意顺序)。

我知道如何搜索同时包含卡特、克林顿和奥巴马的行 ->

:g/.*Carter\&.*Clinton\&.*Obama/p

我知道如何搜索 Carter AND (Clinton OR Bush) ->

:g/.*Carter\&\(.*Clinton\|.*Bush\)/p

(肯定有更好的方法来做到这一点)

但我想不出如何搜索(我已经看了相关问题),例如,搜索布什和克林顿而非卡特,甚至更不用说搜索布什和克林顿而非(卡特或奥巴马)。


1
我没有完整的答案给你,但是你可以使用负向先行断言来实现负字符串匹配。虽然不太美观,但是可以看一下 :help \@<!。如果是我,我会选择在命令行中使用 grep | grep -v 的方法。 - ire_and_curses
@ire_and_curses "@<!" 是负向零宽先行断言,不是正向的。 - ZyX
2个回答

70

要表示 NOT,可以使用负断言 \@!

例如,“NOT Bush” 可以表示为:

^\(.*Bush\)\@!

或者使用\v

\v^(.*Bush)@!

重要提示: 注意前导的^。如果你只使用正向断言(一个匹配和其他任何一个都一样),它是可选的,但对于负向断言来说则是必须的(否则它们仍然可以在行末匹配)。

翻译"Bush AND Clinton AND NOT (Carter OR Obama):":

\v^(.*Bush)&(.*Clinton)&(.*Carter|.*Obama)@!

附言

为了解释 \&\@= 之间的关系:

One&Two&Three

可以互换使用:

(One)@=(Two)@=Three

唯一的区别是\&直接镜像了\|(这应该更明显和自然),而\@=则镜像了Perl的(?=pattern)


Piet Delport:我尝试了你的解决方案,它完美地运行了。非常感谢。但是作为一个新手,我惊讶于Vim成功实现事情的不同方式的数量(包括你的解决方案和ZyX的)。 - ThG
1
Piet - 你的回答很好,和Zyx的一样。我理解你的解决方案仍然使用了Zyx建议避免的&运算符。但我喜欢它,因为更容易看到表达式的实际布尔结构,特别是魔法版本。 - Herbert Sitz
没有任何理由避免使用\&:这是Vim,不是Perl。 :) 即使您计划在Vim和Perl/PCRE中使用正则表达式,将\&\@=都翻译成Perl的语法需要同样的努力:无论如何避免使用\&都不会给您带来任何好处。 - Pi Delport
我建议避免使用,因为1)你可能会习惯于它并且在理解或编写Perl风格的正则表达式时会遇到问题。2)没有负分支,但有负向前查找。为什么我们需要两个不同的东西来表达一个想法? - ZyX
哇,那个 \v 真棒。 - Aaron Gray

15

如果你想在vim中使用Perl风格的正则表达式,忘记\&吧:它是一个vim特有的功能,在vim中没有用处,因为vim也有lookahead。所以任何r1\&r2都可以重写为\%(r1\)\@=r2。但是lookahead更好用,因为它有负面版本,并且在大多数Perl风格的正则表达式引擎中也可用。你的(Bush AND Clinton AND NOT (Carter OR Obama))可以这样表示:

g/^\%(.*\%(Carter\|Obama\)\)\@!\%(.*Bush\)\@=.*Clinton/

或者,使用非常神奇的方法:

g/^\v%(.*%(Carter|Obama))@!%(.*Bush)@=.*Clinton/
请参见:h /\@=
关于内部逻辑:前瞻就像分支一样:对于正则表达式(reg1)@=reg2,假设reg2在位置N(匹配从位置N开始),正则表达式引擎会检查reg1是否也在此位置匹配。如果不匹配,则此位置被丢弃,正则表达式引擎尝试下一个可能的reg2匹配。负向前瞻也是一样的,但区别在于如果reg1匹配,则正则表达式引擎会丢弃该位置。
示例:
正则表达式:(.b)@!a
字符串:aba
- 找到匹配项:a在位置0匹配(aba)。尝试匹配前瞻:.匹配aaba)和b匹配baba),前瞻匹配成功,丢弃位置。 - 位置1(aba)不匹配a。 - 找到匹配项:a在位置2匹配(aba)。尝试匹配前瞻:.匹配aaba),但b不匹配:没有符号剩余,前瞻失败。结果:正则表达式在位置2匹配。

ZyX:首先,感谢您的帮助:我尝试了您的方法,它当然有效。但问题是,我不理解您的正则表达式的内部逻辑。既然这是一个论坛而不是教室,我会遵循您的建议,在Vim帮助中寻找答案(如果对于一个正则表达式新手来说不太难的话)。 - ThG
我不知道。我该怎么做? - ThG
@ThG 在问题左侧的列中,您可以看到一个向上的三角形、一个数字、一个向下的三角形和一个勾号。后者用于接受答案,三角形用于对问题进行投票。您必须阅读FAQ,其中描述了如何接受答案。 - ZyX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接