首页 ┆网站地图 ┆游戏资讯 ┆天龙八部 ┆资源下载 ┆淘宝网购物 ┆淘宝数码产品 ┆淘宝数码相机 
设为首页
加入收藏
联系我们
高级搜索
您当前的位置: 主页 > 编程相关 > 正则表达式 > 正则表达式中贪婪和非贪婪(惰性)匹配的区别与效率问题
正则表达式中贪婪和非贪婪(惰性)匹配的区别与效率问题
来源: 发布时间:2010-02-05 浏览:人次  字体:[  
正则表达式中贪婪和非贪婪(惰性)匹配的区别与效率问题:
什么是贪婪模式匹配?
正则中“贪婪模式匹配”原则是: 当解释器将代码中的字符解析成一个个的 编译器在处理代码时眼中看到的最小语法单元时,编译器会使用一种贪婪匹配算法,也就是说会尽可能让一个单元包含更多的字符。
非贪婪匹配的效率
可能有不少的人和我一样,有过这样的经历:当我们要匹配类似 "<td>内容</td>" 或者 "加粗" 这样的文本时,我们根据正向预搜索功能写出这样的表达式:"<td>([^<]|<(?!/td>))*</td>" 或者 "<td>((?!</td>).)*</td>"。
当发现非贪婪匹配之时,恍然大悟,同样功能的表达式可以写得如此简单:"<td>.*?</td>"。 顿时间如获至宝,凡是按边界匹配的地方,尽量使用简捷的非贪婪匹配 ".*?"。特别是对于复杂的表达式来说,采用非贪婪匹配 ".*?" 写出来的表达式的确是简练了许多。
然而,当一个表达式中,有多个非贪婪匹配时,或者多个未知匹配次数的表达式时,这个表达式将可能存在效率上的陷阱。有时候,匹配速度慢得莫名奇妙,甚至开始怀疑正则表达式是否实用。

效率陷阱的产生:
非贪婪匹配:“如果少匹配就会导致整个表达式匹配失败的时候,与贪婪模式类似,非贪婪模式会最小限度的再匹配一些,以使整个表达式匹配成功。”
具体的匹配过程是这样的:
"非贪婪部分" 先匹配最少次数,然后尝试匹配 "右侧的表达式"。
如果右侧的表达式匹配成功,则整个表达式匹配结束。如果右侧表达式匹配失败,则 "非贪婪部分" 将增加匹配一次,然后再尝试匹配 "右侧的表达式"。
如果右侧的表达式又匹配失败,则 "非贪婪部分" 将再增加匹配一次。再尝试匹配 "右侧的表达式"。
依此类推,最后得到的结果是 "非贪婪部分" 以尽可能少的匹配次数,使整个表达式匹配成功。或者最终仍然匹配失败。
当一个表达式中有多个非贪婪匹配,以表达式 "d(\w+?)d(\w+?)z" 为例,对于第一个括号中的 "\w+?" 来说,右边的 "d(\w+?)z" 属于它的 "右侧的表达式",对于第二个括号中的 "\w+?" 来说,右边的 "z" 属于它的 "右侧的表达式"。
当 "z" 匹配失败时,第二个 "\w+?" 会 "增加匹配一次",再尝试匹配 "z"。如果第二个 "\w+?" 无论怎样 "增加匹配次数",直至整篇文本结束,"z" 都不能匹配,那么表示 "d(\w+?)z" 匹配失败,也就是说第一个 "\w+?" 的 "右侧" 匹配失败。此时,第一个 "\w+?" 会增加匹配一次,然后再进行 "d(\w+?)z" 的匹配。循环前面所讲的过程,直至第一个 "\w+?" 无论怎么 "增加匹配次数",后边的 "d(\w+?)z" 都不能匹配时,整个表达式才宣告匹配失败。
其实,为了使整个表达式匹配成功,贪婪匹配也会适当的“让出”已经匹配的字符。因此贪婪匹配也有类似的情况。当一个表达式中有较多的未知匹配次数的表达式 时,为了让整个表达式匹配成功,各个贪婪或非贪婪的表达式都要进行尝试减少或增加匹配次数,由此容易形成一个大循环的尝试,造成了很长的匹配时间。本文之 所以称之为“陷阱”,因为这种效率问题往往不易察觉。
举例:"d(\w+?)d(\w+?)d(\w+?)z" 匹配 "ddddddddddd..." 时,将花费较长一段时间才能判断出匹配失败 。

(?:pattern)
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern)
正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)
负向预查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

效率陷阱的避免:
避免效率陷阱的原则是:避免“多重循环”的“尝试匹配”。并不是说非贪婪匹配就是不好的,只是在运用非贪婪匹配的时候,需要注意避免过多“循环尝试”的问题。
情况一:对于只有一个非贪婪或者贪婪匹配的表达式来说,不存在效率陷阱。也就是说,要匹配类似 "<td> 内容 </td>" 这样的文本,表达式 "<td>([^<]|<(?!/td>))*</td>" 和 "<td>((?!</td>).)*</td>" 和 "<td>.*?</td>" 的效率是完全相同的。
情况二:如果一个表达式中有多个未知匹配次数的表达式,应防止进行不必要的尝试匹配。
比如,对表达式 "<script language='(.*?)'>(.*?)</script>" 来说, 如果前面部分表达式在遇到 "<script language='javascript'>" 时匹配成功后,而后边的 "(.*?)</script>" 却匹配失败,将导致第一个 ".*?" 增加匹配次数再尝试。而对于表达式真正目的,让第一个 ".*?" 增加匹配成“javascript'>”是不对的,因此这种尝试是不必要的尝试。
因此,对依靠边界来识别的表达式,不要让未知匹配次数的部分跨过它的边界。前面的表达式中,第一个 ".*?" 应该改写成 "[^']*"。后边那个 ".*?" 的右边再没有未知匹配次数的表达式,因此这个非贪婪匹配没有效率陷阱。于是,这个匹配脚本块的表达式,应该写成:"<script language='([^']*)'>(.*?)</script>" 更好。
↓下一篇:没有了
 
相 关 文 章 发布商链接
·正则表达式中后向引用、零宽断言、负...
·php开发中常用正则表达式收集
·用javascript验证表单数据正则表达式...
·replace函数的用法及其参数/g/i介绍
·用javascript正则表达式实现指定关键...
·用javascript正则去掉字符串段首和段...
·PHP中preg_match_all函数用法使用详...
·用php正则表达式提取URL中的域名
·用php正则表达式去掉字符串的所有空...
·js正则表达式中的exec方法用法简介
 §最新评论:(评论内容只代表网友观点,与本站立场无关!)淘宝店铺一条街淘宝运动鞋淘宝网热门男装
网名:  验证码:  【所有评论】【↑返回顶部
评 分:12345
评论内容:(不能超过500字,请自觉遵守互联网相关政策法规。[按 Ctrl+Enter 可直接提交]
注意:请勿在本站发布政治话题、色情及违反法律的内容。
IT知道网 声明:刊登此文章是为了传递更多信息,文章内容仅供参考,转载请注明出处。
推 荐 文 章
·目前写的最好的正则表达式教...
·最为常用的正则表达式收集整...
·正则表达式30分钟快速入门教...
·获取图片地址的正则表达式
·正则表达式提取或校验网页脚...
·用正则表达式验证ip地址和身...
·正则表达式实现Html转换UBB程
·正则表达式实现将首字单词转...
·利用正则表达式去掉html代码
·论坛E-mail验证的正则表达式...
·解释正则表达式中的全部符号
推 荐 主 题
java专题.net开发php学习
数据库windows7Word技巧
天龙八部QQ技巧IT职场
javascriptPhotoShop 淘宝购物
图 文 推 荐
正则表达式30分钟快速入门教程正则表达式30分钟快速入门教程
热 门 文 章
·用正则表达式验证ip地址和身...
·javascript正则表达式判断中...
·获取图片地址的正则表达式
·用javascript正则表达式验证...
·用php正则表达式提取URL中的...
·javascript中的match函数使用...
·目前写的最好的正则表达式教...
·用php正则表达式去掉字符串的...
·js正则表达式中的exec方法用...
·用javascript获取地址栏url参...
·用javascript正则去掉字符串...
·PHP中preg_match_all函数用法...
热 门 关 键 字
 网站首页 - 关于本站 - 加入收藏 - 网站地图 - 淘宝购物 - 在线留言 - 广告服务 - 返回顶部
Copyright © 2007 IT知道网.[冀ICP备07026896号]. All Rights Reserved .