先行断言,是当扫描指针位于某处时,引擎会尝试匹配指针还未扫过的字符,先于指针到达该字符,故称为先行。
后行断言,引擎会尝试匹配指针已扫过的字符,后于指针到达该字符,故称为后行。
正则表达式的先行断言(lookahead)和后行断言(lookbehind)一共有四种形式:
(?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion) :
(?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)
(?<=pattern) 零宽正向后行断言(zero-width positive lookbehind assertion)
(?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)
(?=pattern) 正向先行断言 :代表字符串中的一个位置, 紧接该位置之后 的字符序列 能够匹配 pattern。
a(?=b)b匹配abc的时候为:
(?!pattern) 负向先行断言 :代表字符串中的一个位置, 紧接该位置之后 的字符序列 不能匹配 pattern。
工作过程和正向类似。
(?<=pattern) 正向后行断言 :代表字符串中的一个位置, 紧接该位置之前 的字符序列 能够匹配 pattern。
b(?<=b)c 匹配“abc"的时候为:
a不是b,下一个b是b,发现是后行断言,当前位置(在c处)的前面判断是否符合pattern,c前面是b,符合断言,继续从b后即c开始匹配,符合c,匹配结果为bc。
(?<!pattern) 负向后行断言 :代表字符串中的一个位置, 紧接该位置之前 的字符序列 不能匹配 pattern。
工作过程和正向类似。
(?: X ):非捕获组,分组用于匹配但是不捕获,例如:a(?:bc)匹配"abc",group()输出abc,但是groupCount()为0,因为唯一的分组是 (?:bc ),但是它是非捕获组,所以不会捕获,因此为0
注:group()=group(0),从group(1)开始表示子捕获组,也就是用()括起来的分组
(?idmsux-idmsux)Nothing,但是将匹配标志i d m s u x on - off 匹配标志,?i、?d等标志有特殊含义,如?i表示不区分大小写:(?i)abc(?-i)abc,刚刚开始打开不区分大小写,在?i之间加"-"表示关闭不区分大小写。 |
(?idmsux-idmsux: X ) X ,作为带有给定标志 i d m s u x on - off
与上面类似, (?i)abc(?-i)abc可以写成(?i:abc)(?-i:abc)
(?>X)预测其后是X,但是不进行字符位置回溯,因此会改变字符串引擎匹配位置指针。
例如:
(?>b)b则不能匹配"bc"中的b;(?>b)c则可以匹配"bc"中的bc。
正大表达式数量词
Greedy 数量词(默认)
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
也就是说对于 abcd123这个原始文本来说 .*3 是可以匹配的,因为点可以匹配任何字符,*表示可以匹配0次或者多次,全部吃入abcd123发现.*匹配了,但是后面有个3却无法匹配,因此就回溯一个字符,也就是.*只匹配abcd12 刚好整个表达式可以匹配。这就是贪吃,可以回溯。
Reluctant 数量词
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
对于Reluctant 来说,就是Greedy的一个相反的匹配模式,他从左到有一个一个开始匹配,而不是整个字符串一个一个回溯。同样对于上面这个例子,abcd123, 用.*?3 也是匹配的,因为从左到右,一个一个看只有全部才能匹配,而对于 模式.+?来说,只匹配最左边的a字符,如果.*?意味着没有匹配任何字符。
Possessive 数量词
X?+ X,一次或一次也没有
X*+ X,零次或多次
X++ X,一次或多次
X{n}+ X,恰好 n 次
X{n,}+ X,至少 n 次
X{n,m}+ X,至少 n 次,但是不超过 m 次
它和greedy类似,也是全部吃入,但是唯一不同的是它不回溯,所以对于上面的abcd123这个例子,.*+3是不匹配的。