在正则表达式中,有一部分内容并不容易通过文档解释就能搞清楚,那就是预查。预查包括正向预查,反向预查,细分了还各自有肯定预查和否定预查。
(?=pattern)
正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 —— Wikipedia正则表达式字条
这段解释可以说是啥都没讲清楚。其实其中有一个关键点,就是预查不消耗字符。正则表达式是对给定的字符串进行匹配,也就可以说,一般匹配了一个字符后,该字符就被消耗,就不能被Regular Expression的其他部分匹配了。
但是预查不是,因为它不消耗字符。用Javascript做个实验,先想想这段代码会输出什么?
var s = "abc"
console.log(/a(?=b)bc/.test(s))
console.log(/a(b)test(s))
答案就是
true
false
/a(?=b)bc/
中的正向肯定预查(?=b)
匹配了a后面的字母b,但是并没有消耗它,所以,后面再跟一个“bc”串,这就完整地匹配了字符串“abc”。其实,它的真正意义应该是确定了这个字母a,因为不是每个字母a后面都会跟一个字母b的!
而a(b)bc
因为匹配并消耗了字母a后面的b,再来添加一个“bc”串的时候,就变成了“abbc”,就不能匹配字符串“abc”。
到这,估计后面的正向否定预查就没什么问题了,以及反向预查,只不过是类似的,但是位置变了。
(?<=pattern)
这是反向肯定预查,因为Javascript不支持反向预查,所以以下用Python实现
import re
re.match(r'a(?<=a)bc',"abc") is not None #输出True