吐血推荐--孟岩的《理解正则表达式》
2007-03-06 09:51
246 查看
没想到孟岩这么风趣,我觉得这篇文章写的太好了,对于对正则表达式还觉得很莫名其妙的人来说,这篇文章会给你豁然开朗的感觉。
摘录:
用正则式/perl|perlman/来匹配文本 ‘perlman book’。如果是NFA,则以正则式为导向,手里捏着正则式,眼睛看着文本,一个字符一个字符的吃,吃完 ‘perl’ 以后,跟第一个子正则式/perl/已经匹配上了,于是记录在案,往下再看,吃进一个 ‘m’,这下糟了,跟子式/perl/不匹配了,于是把m吐出来,向上汇报说成功匹配 ‘perl’,不再关心其他,也不尝试后面那个子正则式/perlman/,自然也就看不到那个更好的答案了。
如果是DFA,它是以文本为导向,手里捏着文本,眼睛看着正则式,一口一口的吃。吃到/p/,就在手里的 ‘p’ 上打一个钩,记上一笔,说这个字符已经匹配上了,然后往下吃。当看到 /perl/ 之后,DFA不会停,会尝试再吃一口。这时候,第一个子正则式已经山穷水尽了,没得吃了,于是就甩掉它,去吃第二个子正则式的/m/。这一吃好了,因为又匹配上了,于是接着往下吃。直到把正则式吃完,心满意足往上报告说成功匹配了 ‘perlman’。
由此可知,要让NFA正确工作,应该使用 /perlman|perl/ 模式。
通过以上例子,可以理解为什么NFA是最左子式匹配,而DFA是最长左子式匹配。实际上,如果仔细分析,关于NFA和DFA的不同之处,都可以找出道理。而明白这些道理,对于有效应用正则表达式是非常有意义的。
4. 理解greedy和lazy量词
由于日常遇到的正则表达式引擎全都是NFA,所以缺省都采用greedy量词。Greedy量词的意思不难理解,就是对于/.*/、/\w+/这样的“重复n”次的模式,以贪婪方式进行,尽可能匹配更多字符,直到不得以罢手为止。
举一个例子,以 /<.*>/ 模式匹配 ‘<book> <title> Perl Hacks </title> </book>\t’文本,匹配结果不是 ‘<book>’,而是 ‘<book> <title> Perl Hacks </title> </book>’。原因就在于NFA引擎以贪婪方式执行“重复n次”的命令。让我们来仔细分析一下这个过程。
条款3指出,NFA的模型是以正则式为导向,拿着正则式吃文本。在上面的例子里,当它拿着/.*/这个正则式去吃文本的时候,缺省情况下它就这么一路吃下去,即使碰到 ‘>’字符也不罢手——既然 /./ 是匹配任意字符, ‘>’ 当然也可以匹配!所以就尽管吃下去,直到吃完遇到结尾(包括\t字符)也不觉得有什么不对。这个时候它突然发现,在正则表达式最后还有一个 />/,于是慌了神,知道吃多了,于是就开始一个字符一个字符的往回吐,直到吐出倒数第二个字符 ‘>’,完成了与正则式的匹配,才长舒一口气,向上汇报,匹配字符串从第一个字符 ‘<’ 开始,到倒数第二个字符 ‘>’结束,即‘<book> <title> Perl Hacks </title> </book>’。
Greedy量词的行为有时确实是用户所需要的,有时则不是。比如在这个例子里,用户可能实际上想得到的是 ‘book’ 串。怎么办呢?这时候lazy量词就派上用场了。把模式改为/<.*?>/就可以得到 ‘book’。这个加在 ‘*’号后面的 ‘?’ 把greedy量词行为变成lazy量词行为,从而由尽量多吃变为尽量少吃,只要吃到一个 ‘>’立刻停止。
问号在正则表达式里用途最广泛,这里是很重要的一个用途。
摘录:
用正则式/perl|perlman/来匹配文本 ‘perlman book’。如果是NFA,则以正则式为导向,手里捏着正则式,眼睛看着文本,一个字符一个字符的吃,吃完 ‘perl’ 以后,跟第一个子正则式/perl/已经匹配上了,于是记录在案,往下再看,吃进一个 ‘m’,这下糟了,跟子式/perl/不匹配了,于是把m吐出来,向上汇报说成功匹配 ‘perl’,不再关心其他,也不尝试后面那个子正则式/perlman/,自然也就看不到那个更好的答案了。
如果是DFA,它是以文本为导向,手里捏着文本,眼睛看着正则式,一口一口的吃。吃到/p/,就在手里的 ‘p’ 上打一个钩,记上一笔,说这个字符已经匹配上了,然后往下吃。当看到 /perl/ 之后,DFA不会停,会尝试再吃一口。这时候,第一个子正则式已经山穷水尽了,没得吃了,于是就甩掉它,去吃第二个子正则式的/m/。这一吃好了,因为又匹配上了,于是接着往下吃。直到把正则式吃完,心满意足往上报告说成功匹配了 ‘perlman’。
由此可知,要让NFA正确工作,应该使用 /perlman|perl/ 模式。
通过以上例子,可以理解为什么NFA是最左子式匹配,而DFA是最长左子式匹配。实际上,如果仔细分析,关于NFA和DFA的不同之处,都可以找出道理。而明白这些道理,对于有效应用正则表达式是非常有意义的。
4. 理解greedy和lazy量词
由于日常遇到的正则表达式引擎全都是NFA,所以缺省都采用greedy量词。Greedy量词的意思不难理解,就是对于/.*/、/\w+/这样的“重复n”次的模式,以贪婪方式进行,尽可能匹配更多字符,直到不得以罢手为止。
举一个例子,以 /<.*>/ 模式匹配 ‘<book> <title> Perl Hacks </title> </book>\t’文本,匹配结果不是 ‘<book>’,而是 ‘<book> <title> Perl Hacks </title> </book>’。原因就在于NFA引擎以贪婪方式执行“重复n次”的命令。让我们来仔细分析一下这个过程。
条款3指出,NFA的模型是以正则式为导向,拿着正则式吃文本。在上面的例子里,当它拿着/.*/这个正则式去吃文本的时候,缺省情况下它就这么一路吃下去,即使碰到 ‘>’字符也不罢手——既然 /./ 是匹配任意字符, ‘>’ 当然也可以匹配!所以就尽管吃下去,直到吃完遇到结尾(包括\t字符)也不觉得有什么不对。这个时候它突然发现,在正则表达式最后还有一个 />/,于是慌了神,知道吃多了,于是就开始一个字符一个字符的往回吐,直到吐出倒数第二个字符 ‘>’,完成了与正则式的匹配,才长舒一口气,向上汇报,匹配字符串从第一个字符 ‘<’ 开始,到倒数第二个字符 ‘>’结束,即‘<book> <title> Perl Hacks </title> </book>’。
Greedy量词的行为有时确实是用户所需要的,有时则不是。比如在这个例子里,用户可能实际上想得到的是 ‘book’ 串。怎么办呢?这时候lazy量词就派上用场了。把模式改为/<.*?>/就可以得到 ‘book’。这个加在 ‘*’号后面的 ‘?’ 把greedy量词行为变成lazy量词行为,从而由尽量多吃变为尽量少吃,只要吃到一个 ‘>’立刻停止。
问号在正则表达式里用途最广泛,这里是很重要的一个用途。
相关文章推荐
- 吐血推荐 36招搞定电脑一切难题
- Android技巧分享——Android开发超好用工具吐血推荐(转)
- JTree用法及JTree使用经验总结(吐血推荐)
- 如何建立 iPhone 开发环境(中文windows)上部 (吐血推荐)
- 吐血推荐cookie和session
- 一位空姐对飞机上26位明星的印象(吐血推荐)
- 外贸人通过网络找客户的九大方法!(吐血推荐!!)
- 电子学习资料/电子设计/电子竞赛/产品设计/产品开发(吐血推荐)
- 【转】使用Dotfuscator混淆处理融入DotNet ClickOnce发布(超经典,测试已通过,转发的,吐血推荐,不看也收藏了)简称:混淆发布
- 33家国内外知名的手机广告平台的SDK名单汇总,吐血推荐
- [吐血推荐]String in Java
- 吐血推荐: 深入理解java 虚拟机
- 超多单机游戏喽,吐血推荐!
- 【吐血推荐一下】爆强的搞笑签名档
- 转: 私人珍藏的Chrome插件,吐血推荐
- 吐血推荐,本人真实的一次数据修复过程,都是ghost惹的祸!
- 模拟集成电路学习历程-吐血推荐[zz]
- 吐血推荐博客
- 构建一个.net Remoting 程序(真正的三层结构)_吐血推荐
- 腾讯后台开发面试总结,转载,吐血推荐!!