正则表达式的先行断言(lookahead)和后行断言(lookbehind)
正则表达式的先行断言(lookahead)和后行断言(lookbehind)
正则表达式的先行断言和后行断言一共有 4 种形式:
(?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion)
(?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)
(?<=pattern) 零宽正向后行断言(zero-width positive lookbehind assertion)
(?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)

理解方式
看图更适合理解, 图中的reg是目标,它在前面就是先行,在后面就是后行,脑中应当忘记零宽二字,
正向先行断言 负向先行断言
正向后行断言 负向后行断言
何谓零宽?
因为只匹配位置
正向先行断言
-
re(?=gular)匹配a regular expression
匹配某个位置之前的re,这个位置总不能用手指头指给你看吧?于是就有了标记物,"gular"就是标记物,它标记了
一个位置,最终匹配的是这个位置之前的re -
"(?=他)的"匹配"你的爷爷砍死了他的爸爸"
匹配的目标是"的"字,更具体点是他后面的"的"字,更更具体地说是"他"字后面的位置的后面的"的"字 -
(?=中华)人民(?=共和国)
匹配的目标是人民,他的前面必须是中华,后面必须是共和国
负向先行断言
- 例如对 "regex represents regular expression" 这个字符串,要想匹配除 regex 和 regular 之外的 re,可以用 re(?!g),该表达式限定了 re 右边的位置,这个位置后面不是字符 g。
负向和正向的区别,就在于该位置之后的字符能否匹配括号中的表达式。
正向后行断言
- 代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配 pattern。
例如对 regex represents regular expression 这个字符串,有 4 个单词,要想匹配单词内部的 re,但不匹配单词开头的 re,可以用 (?<=\w)re,单词内部的 re,在 re 前面应该是一个单词字符。
之所以叫后行断言,是因为正则表达式引擎在匹配字符串和表达式时,是从前向后逐个扫描字符串中的字符,并判断是否与表达式符合,当在表达式中遇到该断言时,正则表达式引擎需要往字符串前端检测已扫描过的字符,相对于扫描方向是向后的。
负向后行断言
- 代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配 pattern。
例如对 "regex represents regular expression" 这个字符串,要想匹配单词开头的 re,可以用 (?<!\w)re。单词开头的 re,在本例中,也就是指不在单词内部的 re,即 re 前面不是单词字符。当然也可以用 \bre 来匹配。
关于先行(lookahead)和后行(lookbehind)
正则表达式引擎在执行字符串和表达式匹配时,会从头到尾(从前到后)连续扫描字符串中的字符,设想有一个扫描指针指向字符边界处并随匹配过程移动。先行断言,是当扫描指针位于某处时,引擎会尝试匹配指针还未扫过的字符,先于指针到达该字符,故称为先行。后行断言,引擎会尝试匹配指针已扫过的字符,后于指针到达该字符,故称为后行。
先行和后行:
后行断言 (?<=pattern)、(?<!pattern) 中,有个小于号,同时也是箭头,对于自左至右的文本方向,这个箭头是指向后的,这也比较符合我们的习惯。把小于号去掉,就是先行断言。
关于正向(positive)和负向(negative)
正向就表示匹配括号中的表达式,负向表示不匹配。
正向和负向
不等于 (!=)、逻辑非 (!) 都是用 !号来表示,所以有 ! 号的形式表示不匹配、负向;将 ! 号换成 = 号,就表示匹配、正向。
我们经常用正则表达式来检测一个字符串中包含某个子串,要表示一个字符串中不包含某个字符或某些字符也很容易,用 [^...] 形式就可以了。要表示一个字符串中不包含某个子串(由字符序列构成)呢?
用 [^...] 这种形式就不行了,这时就要用到(负向)先行断言或后行断言、或同时使用。
^((?<!that).)*this((?<!that).)*$
或
^(.(?!that))*this(.(?!that))*$
浙公网安备 33010602011771号