[正则表达式]PCRE环视功能
设想一下这个问题,假设为了方便长串数字的阅读性,需要为其添加逗号作为分隔,需要怎么做呢?
2569836495 =》 2,569,836,495
正则表达式的匹配通常是从左往右的,这导致无法使用类似[\d]{3}这样的方法去解决问题,因为数字是从右边结算的
用s/([\d]{3})/$1,/g处理上面的数字,只会得到这样的结果
2569836495 =》 256,983,649,5
显然这是错误的标记方法
幸好PCRE提供了[顺序环视],和[逆序环视]功能
[顺序环视]:(?=REG),例如(?=\d),将会匹配右边符合\d条件的位置。
[逆序环视]:(?<=REG),例如(?<=\d),将会匹配左边符合\d条件的位置。
注意:两个匹配方式都强调了“位置”二字,因为环视匹配模式,只匹配位置。
这个例子说明一下:
现有字符串:"SELECT * FROM",匹配表达式:(?=SELECT)
表达式的意思是,匹配满足括号内的条件(这里是SELECT)的字符的左边位置
结果将会是这样:"[我是位置,我被匹配了]SELECT * FROM"
还不能理解的话,继续修改一下表达式:(?=SELECT)SEL
此时红色字体部分被匹配了,"SELECT * FROM"
解析一下:(?=SELECT)匹配了"[我是位置,我被匹配了]SELECT * FROM",接下来从这个位置开始,需要紧接着SEL,于是"SELECT * FROM"被匹配了。
而逆序环视也是差不多的原理,只不过匹配方式是从左起
还是使用刚才的字符串:"SELECT * FROM",匹配表达式:(?<=SELECT)
表达式的意思是,匹配满足括号内的条件(这里是SELECT)的字符的右边位置
结果将会是这样:"SELECT[我是位置,我被匹配了] * FROM"
还不能理解的话,继续修改一下表达式:ECT(?<=SELECT)
此时红色字体部分被匹配了,"SELECT * FROM"
解析一下:ECT首先是要被匹配的,接下来必须紧接着匹配SELECT的右边位置才能完成整个匹配。
再来一个结合了顺序和逆序环视的例子:(?<=SELECT).*(?=FROM)
结果是SELECT和FROM之间的字符被匹配了,"SELECT * FROM",注意结果是包括的空格哦,没显示红色部分是因为空格标注不了红色。。。
好了,完成文章开头给出的问题:左侧必须是数字(?<=\d),右侧必须是连贯的3个数字的倍数并且以这样的方式结束的字符(?=(?:[\d]{3})+\b)
连贯起来就是这样的位置(?<=\d)(?=(?:[\d]{3})+\b)
如果不能理解,回头看多几遍介绍,一定会明白的。
明白了上面两种语法,接下来的环视否定就可以很容易理解了
[顺序环视否定]:(?!REG),例如(?!\d),将会匹配右边符合除\d条件的位置。
[逆序环视否定]:(?<!REG),例如(?<!\d),将会匹配左边符合除\d条件的位置。
备注:
JavaScript不支持逆向环视,但是支持正向环视
Perl和Phython的逆向环视结构只能匹配固定长度的文本。使用(?<!\w)和(?<!this|that)不会出错,但是(?<!books?)和(?<!^\w+:)则不行,因为它们匹配的文本的长度是不确定的。某些情况下,(?<!books?)可以重写为(?<!book)(?<!books),尽管第一眼看上去它并不好理解