精通正则表达式七:占有优先量词和固化分组

来源:互联网 发布:linux 覆盖文件夹 编辑:程序博客网 时间:2024/04/29 11:00

定义

占有优先量词:

?+ *+ ++ {m,n}+

占有优先量词与匹配优先量词很相似,只是它们从来不会交还已经匹配的字符。
固化分组:

(?>...)       ...是指具体内容

固化分组的内容与正常的匹配并无区别,只是当匹配完括号中的内容后,括号中的备用状态会全部舍去。

例子

将所有的小数保留三位,规则如下:如果小数位数第三位不为0保留三位,如果小数位数少于三位或第三位为0,保留两位小数。
首先可以用匹配优先量词去做:
在Mac终端下运行如下命令:

perl -p -i -e 's/(\.\d\d[1-9]?)\d*/$1/g' test.txt

运行前test.txt中的内容如下:
这里写图片描述
运行后:
这里写图片描述
这样做肯定是没问题的,但是在处理最后一个数字1.345时,正则表达式相当于是先匹配了’.345’,然后又用’.345’去替换,白费功夫。如何才能避免这种情况,使其更加高效呢?这就可以用占有优先量词和固化分组了。
占有优先量词:

perl -p -i -e 's/(\.\d\d[1-9]?+)\d+/$1/g' test.txt

当正则表达式匹配到’1.345’会怎样呢?首先匹配前面的‘.34’,匹配到’5’时,因为是匹配优先,所以‘[1-9]?+’会先匹配’5’,又因为是占有优先,所以当后面的’\d+’匹配不成功时,不会交还字符,从而导致匹配失败,就不会替换,这正是我们想要的效果。
固化分组:

(\.\d\d(?>[1-9]?))\d+

同样的道理,当匹配到’5’时,因为是匹配优先,所以‘(?>[1-9]?)’会匹配‘5’,有因为是固化分组,所以当后面的’\d+’匹配不成功时,不会交还字符,从而导致匹配失败。

用肯定环视模拟固化分组

有些流派并不支持占有优先量词和固化分组,比如JavaScript,这是我们就可以用肯定环视来模拟固化分组:

.\d\d(?=([1-9]?))\1\d+

环视结构也有备用状态,当环视结构匹配完后,环视结构就会抛弃其内部的备用状态:
这里写图片描述
首先来看第一个数字,当匹配到‘.23’后,开始匹配环视结构内部,因为‘[1-9]?’是匹配优先,所以会先匹配‘4’,此时环视结构内部有一个备用状态,就是不匹配任何字符。继续往后,环视结构匹配结束,抛弃环视结构内部的那个备用状态,继续往后匹配。因为环视结构是不匹配任何字符的,它只是看一下后面是不是要匹配的内容,所以用反向引用‘\1’来匹配刚刚环视结构里的内容,‘\d+’匹配后面的‘980’。

当匹配第二个数字时,也是先匹配到‘.23’,开始匹配环视结构内部,因为‘[1-9]?’是匹配优先,所以会尝试匹配‘0’,此时它有一个备用状态,就是不匹配任何字符。发现无法匹配‘0’,启用备用状态,就是什么都不匹配,环视结构匹配成功,因为环视结构内部没有匹配到任何东西,多以反向引用‘\1’也不会匹配任何字符,‘\d+’匹配后面的‘00293’。

阅读全文
0 0
原创粉丝点击