Vim正则expression式:如何searchA和B不是C

我有很多包含美国总统卡特,布什,克林顿,奥巴马的名字。 一些包含这些名称中的一个,大约2个,大约3个,其中一些全部4个(以任何顺序)。

我知道如何寻找卡特和克林顿以及奥巴马 – >

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

我知道如何寻找卡特(克林顿或布什) – >

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

(当然有更好的方法来做到这一点)

但是我无法想象如何search(我也查看了相关的问题),例如布什和克林顿不是卡特,更不用说如何search布什和克林顿(卡特或奥巴马)。

要表示一个NOT,请使用否定断言\@!

例如,“不布什”将是:

 ^\(.*Bush\)\@! 

或使用\v

 \v^(.*Bush)@! 

重要:请注意领导^ 。 如果只使用肯定断言(一个匹配与其他任何匹配一样好),那么它是可选的,但需要锚定否定断言(否则它们仍然可以在行尾匹配)。

翻译“布什和克林顿而不是(卡特或奥巴马)”:

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

附录

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

 One&Two&Three 

可以互换:

 (One)@=(Two)@=Three 

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

如果你想在vim之后使用Perl风格的正则expression式,忘记\& vim:这是一个vim特有的function,因为vim也有向前看,所以任何r1\&r2都可以被重写为\%(r1\)\@=r2 。 但是前瞻更好,因为它有一个负面的版本,并且在大多数Perl风格的正则expression式引擎中也是可用的。 你们(Bush AND Clinton AND NOT (Carter OR Obama))可以用以下方式表示:

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

或者,非常神奇:

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

请参阅:h /\@=

关于内部逻辑:先行就像分支:对于正则expression式(reg1)@=reg2假设reg2在位置N匹配(匹配从位置N开始),则正则expression式引擎检查reg1是否也在此位置匹配。 如果不是,那么该位置将被丢弃,并且正则expression式引擎会尝试下一个可能的reg2匹配项。 相同的负面预测,但不同的是正则expression式引擎丢弃的位置,如果reg1匹配。


例:

正则expression式:(. (.b)@!a

string: aba

  1. find匹配:在位置0( a baa匹配。 试图匹配前瞻: . 匹配aa ba )和b匹配ba b a ),超前匹配,丢弃位置。
  2. 位置1( a b a )与a不匹配。
  3. find匹配:在位置2 a匹配( ab a )。 试图匹配前瞻: . 匹配( ab a ),但是b不匹配:没有符号,预见失败。 结果:正则expression式匹配在位置2。