从Zjmainstay的深入理解正则表达式高级教程中截取的一部分内容:
环视(断言/零宽断言)
环视,在不同的地方又称之为零宽断言,简称断言。
用一句通俗的话解释:
环视,就是先从全局环顾一遍正则,(然后断定结果,)再做进一步匹配处理。
断言,就是先从全局环顾一遍正则,然后断定结果,再做进一步匹配处理。
两个虽然字面不一样,意思却是同一个,都是做全局观望,再做进一步处理。
环视的作用相当于对其所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
环视主要有以下4个用法:(?<=exp)
匹配前面是exp的数据(?<!exp)
匹配前面不是exp的数据(?=exp)
匹配后面是exp的数据(?!exp)
匹配后面不是exp的数据
示例四:(?<=B)AAA
匹配前面是B的数据,即BAAA匹配,而CAAA不匹配(?<!B)AAA
匹配前面不是B的数据,即CAAA匹配,而BAAA不匹配AAA(?=B)
匹配后面是B的数据,即AAAB匹配,而AAAC不匹配AAA(?!B)
匹配后面不是B的数据,即AAAC能匹配,而AAAB不能匹配
另外,还会看到(?!B)[A-Z]
这种写法,其实它是[A-Z]范围
里,排除B
的意思,前置的(?!B)只是对后面数据的一个限定,从而达到过滤匹配的效果。
因此,环视做排除处理是比较实用的,比如,示例五:
需求:字母、数字组合,不区分大小写,不能纯数字或者纯字母,6-16个字符。 通用正则:^[a-z0-9]{6,16}$ 字母数字组合,6-16个字符 排除纯字母:(?!^[a-z]+$) 排除纯数字:(?!^[0-9]+$) 组合起来:(?!^[a-z]+$)(?!^[0-9]+$)^[a-z0-9]{6,16}$
注意,环视部分是不占宽度的,所以有零宽断言的叫法。
所谓不占宽度,可以分成两部分理解:
1、环视的匹配结果不纳入数据结果
2、环视它匹配过的地方,下次还能用它继续匹配。
如果不是环视,则匹配过的地方,不能再匹配第二次了。
上面示例四体现了:环视的匹配结果不纳入数据结果,它的结果:
(?<=B)AAA 源串:BAAA 结果:AAA
(?<!CAAA AAA
AAA(?= AAAB AAA
(?!AAAC AAA
而示例五体现了:环视它匹配过的地方,下次还能用它继续匹配
因为,整个匹配过程中,正则表达式一共走了3次字符串匹配,第一次匹配不全部是字母,第二次匹配不全部是数字,第三次匹配全部是字母数字组合,6-16个字符。