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。