吐血推荐--孟岩的《理解正则表达式》

本文通过生动的例子介绍了正则表达式中的NFA与DFA的区别,以及如何理解greedy和lazy量词。通过对比两种不同的匹配策略,帮助读者更好地掌握正则表达式的使用技巧。
没想到孟岩这么风趣,我觉得 这篇文章写的太好了,对于对正则表达式还觉得很莫名其妙的人来说,这篇文章会给你豁然开朗的感觉。

摘录:
None.gif 用正则式 / perl | perlman / 来匹配文本 ‘perlman book’。如果是NFA,则以正则式为导向,手里捏着正则式,眼睛看着文本,一个字符一个字符的吃,吃完 ‘perl’ 以后,跟第一个子正则式 / perl / 已经匹配上了,于是记录在案,往下再看,吃进一个 ‘m’,这下糟了,跟子式 / perl / 不匹配了,于是把m吐出来,向上汇报说成功匹配 ‘perl’,不再关心其他,也不尝试后面那个子正则式 / perlman / ,自然也就看不到那个更好的答案了。
None.gif
None.gif如果是DFA,它是以文本为导向,手里捏着文本,眼睛看着正则式,一口一口的吃。吃到
/ p / ,就在手里的 ‘p’ 上打一个钩,记上一笔,说这个字符已经匹配上了,然后往下吃。当看到  / perl /  之后,DFA不会停,会尝试再吃一口。这时候,第一个子正则式已经山穷水尽了,没得吃了,于是就甩掉它,去吃第二个子正则式的 / m / 。这一吃好了,因为又匹配上了,于是接着往下吃。直到把正则式吃完,心满意足往上报告说成功匹配了 ‘perlman’。
None.gif
None.gif由此可知,要让NFA正确工作,应该使用 
/ perlman | perl /  模式。
None.gif
None.gif通过以上例子,可以理解为什么NFA是最左子式匹配,而DFA是最长左子式匹配。实际上,如果仔细分析,关于NFA和DFA的不同之处,都可以找出道理。而明白这些道理,对于有效应用正则表达式是非常有意义的。
None.gif
4 . 理解greedy和lazy量词
None.gif由于日常遇到的正则表达式引擎全都是NFA,所以缺省都采用greedy量词。Greedy量词的意思不难理解,就是对于
/ . */ / \w +/ 这样的“重复n”次的模式,以贪婪方式进行,尽可能匹配更多字符,直到不得以罢手为止。
None.gif
None.gif举一个例子,以 
/< . *>/  模式匹配 ‘ < book >   < title >  Perl Hacks  </ title >   </ book > \t’文本,匹配结果不是 ‘ < book > ’,而是 ‘ < book >   < title >  Perl Hacks  </ title >   </ book > ’。原因就在于NFA引擎以贪婪方式执行“重复n次”的命令。让我们来仔细分析一下这个过程。
None.gif
None.gif条款3指出,NFA的模型是以正则式为导向,拿着正则式吃文本。在上面的例子里,当它拿着
/ . */ 这个正则式去吃文本的时候,缺省情况下它就这么一路吃下去,即使碰到 ‘ > ’字符也不罢手——既然  / . /  是匹配任意字符, ‘ > ’ 当然也可以匹配!所以就尽管吃下去,直到吃完遇到结尾(包括\t字符)也不觉得有什么不对。这个时候它突然发现,在正则表达式最后还有一个  />/ ,于是慌了神,知道吃多了,于是就开始一个字符一个字符的往回吐,直到吐出倒数第二个字符 ‘ > ’,完成了与正则式的匹配,才长舒一口气,向上汇报,匹配字符串从第一个字符 ‘ < ’ 开始,到倒数第二个字符 ‘ > ’结束,即‘ < book >   < title >  Perl Hacks  </ title >   </ book > ’。
None.gif
None.gifGreedy量词的行为有时确实是用户所需要的,有时则不是。比如在这个例子里,用户可能实际上想得到的是 ‘book’ 串。怎么办呢?这时候lazy量词就派上用场了。把模式改为
/< . *?>/ 就可以得到 ‘book’。这个加在 ‘ * ’号后面的 ‘ ? ’ 把greedy量词行为变成lazy量词行为,从而由尽量多吃变为尽量少吃,只要吃到一个 ‘ > ’立刻停止。
None.gif
None.gif问号在正则表达式里用途最广泛,这里是很重要的一个用途。
None.gif

转载于:https://www.cnblogs.com/jxhwei/archive/2007/03/06/665022.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值