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