正则表达式-学习笔记

原文:http://www.newsmth.net/bbsanc.php?path=%2Fgroups%2Fcomp.faq%2FVIM%2Fusage%2Fregexp%2FM.1180953641.00

常用的正则表达式引擎(NFA)大都提供了Greedy qualifier, Lazy qualifier(在Java中称为Reluctantqualifier)和Atomic grouping(在Java中对应的概念是Possessive qualifier),但开发人员一般用到的只是最普通的,默认的qualifier,许多人甚至根本不了解qualifier的分类。那么,这三个概念的,到底有什么区别呢?

 
先来看Greedy qualifier和Lazy qualifier,要了解这两者的区别,必须引入一个概念,就是回溯(Backtracking)。

简单的说,回溯就是记录已匹配的子表达式的可能状态(例如,待匹配串中为字符aa,正则表达式为a+,则回溯机制会记录:a+既可以匹配a,也可以匹配aa,并选取其中之一作为当前尝试),如果接下来的子表达式无法匹配,就需要回溯,更改之前表达式的状态。

 下面我们来看一个回溯的例子:

若待匹配串为

abcdefg6

正则表达式为

^.*\d$

正则引擎会从左至右开始匹配,因为.可以匹配任何字符,则.*会匹配整个字符串abcdefg6(实际上,每前进一个字符,正则引擎都保存了选择信息以供回溯),此时已经前进到待匹配串的末端,而正则式尚未匹配完成,引擎便会启用回溯机制——\d会对.*说,我来了,吃了我的,给我吐出来J——.*于是回退一位,把6交出来,\d匹配完成,最后,换行符与$匹配,则整个正则式的匹配完成。

 了解了回溯,再来看Greedy qualifier和Lazy qualifier就很容易了。

Greedy qualifier之所以得名,是因为它记录下回溯信息之后,总是尝试“满足”(match)的选项。举例来说,\d?代表匹配一位或零位数字,Greedy qualifier记录下两个选项之后,首先尝试的便是匹配一位数字。

而Lazy qualifier在记录下回溯信息之后,首先尝试的是“不满足”(not match)的选项。仍然举\d?的例子(注意,这里只是为了利用\d?的概念,应用时需要另加修饰符规定\d?为一个Lazy qualifier),如果是Lazy qualifier,则首先尝试“不匹配数字”的分支。

 一般来说,Greedyqualifier是默认的选项,我们通常使用的qualifier就是Greedy qualifier。如果需要采用Lazy qualifier,开发人员需要把\d?写作\d??(在Java语言中,Lazy qualifier的标志是在相应的Greedy qualifier之后加上一个?),正则引擎才能正确识别。

 至此,我们可以看一个例子:

The name “McDonald’s” is said“makudonarudo” in Japenese

如果使用”.*”匹配,则取得“McDonald’s” is said“makudonarudo”

如果使用”.*?”匹配,则取得“McDonald’s”

 
熟练的使用这两种qualifier,能为开发人员提供极大的便利。

然而,仅有这两种qualifier还是不够的,因为回溯需要记录之前的选择分支,很多时候会影响匹配的效率,来看下面的例子:

正则表达式为

^\w+:

待匹配串为

ThisIsAnInefficientMatch

希望匹配的是以新行为开头,以:结尾的一串字符,我们一眼就能看出,待匹配串不包含这种子串,但正则引擎需要进行多次回溯(在匹配:之前,\w+已经匹配了整行,每个字符之前都保留了一个选择分支)才能得出结果,即便换用^\w+?:,仍然需要进行多次无谓的尝试。

 

正因为如此,正则引擎提供了AtomicGrouping的机制。

简单的说,Atomic Grouping的主要功能便是取消回溯,提高效率——如果匹配成功,它与普通的grouping并无区别,但是如果匹配失败,所有位于Atomic Grouping中的状态会全部失效。

来看上一个例子,如果我们为\w+子串加上Atomic Grouping,写作(?>\w+),整个正则表达式变为^(?>\w+):,在group内部,\w+是一个greedy qualifier,将会匹配整行字符,并且记录下多个回溯状态(注意,这里的记录都在AtomicGrouping内部),然后开始匹配:,正则引擎发现:无法匹配,此时无需回溯(?>\w+)内部的分支,而是将它们全盘放弃,这样极大地提高了匹配(主要是匹配失败)的效率。

 
一些语言或许没有提供Atomic Grouping的功能,或者以另一种方式提供,例如Java语言引入了Possessive qualifier,其作用与Atomic Grouping类似,只是写法不同。上面的例子中,Atomic Grouping的(?>\+),用Possessive qualifier,写作\w++。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值