全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

编写高质量的js之正确理解正则表达式回溯

当一个正则表达式扫描目标字符串时,从左到右逐个扫描正则表达式的组成部分,在每个位置上测试能不能找到一个匹配。对于每一个量词和分支,都必须确定如何继续进行。如果是一个量词(如*、+?或者{2,}),那么正则表达式必须确定何时尝试匹配更多的字符;如果遇到分支(通过|操作符),那么正则表达式必须从这些选项中选择一个进行尝试。

当正则表达式做出这样的决定时,如果有必要,它会记住另一个选项,以备返回后使用。如果所选方案匹配成功,正则表达式将继续扫描正则表达式模板,如果其余部分匹配也成功了,那么匹配就结束了。但是,如果所选择的方案未能发现相应匹配,或者后来的匹配也失败了,正则表达式将回溯到最后一个决策点,然后在剩余的选项中选择一个。继续这样,直到找到一个匹配,或者量词和分支选项的所有可能的排列组合都尝试失败后放弃这一过程,然后移动到此过程开始位置的下一个字符上,重复此过程。

例如,下面的代码演示了这一过程是如何通过回溯处理分支的。

/h(ello|appy) hippo/.test("hello there, happy hippo");

上面一行正则表达式用于匹配“hello hippo”或“happy hippo”。测试一开始要查找一个h,目标字符串的第一个字母恰好就是h,立刻就找到了。接下来,子表达式(ello|appy)提供了两个处理选项。正则表达式选择最左边的选项(分支选择总是从左到右进行),检查ello 是否匹配字符串的下一个字符,确实匹配,然后正则表达式又匹配了后面的空格。

然而,在接下来的匹配中正则表达式“走进了死胡同”,因为hippo 中的h 不能匹配字符串中的下一个字母t。此时正则表达式还不能放弃,因为它还没有尝试过所有的选择,随后它回溯到最后一个检查点(在匹配了首字母h 之后的那个位置上)并尝试匹配第二个分支选项。但由于匹配没有成功,而且也没有更多的选项了,正则表达式认为从字符串的第一个字符开始匹配是不能成功的,因此它从第二个字符开始重新进行查找。正则表达式没有找到h,继续向后找,直到第14 个字母才找到,它匹配happy 的那个h。随后正则表达式再次进入分支过程,这次ello 未能匹配,但在回溯之后的第二次分支中,它匹配了整个字符串“happy hippo”,匹配成功了。

再如,下面代码演示了带重复量词的回溯。

var str = "<p>Para 1.</p>" +"<img src='smiley.jpg'>" +"<p>Para 2.</p>" +"<div>Div.</div>";
/<p>.*<\/p>/i.test(str);

正则表达式先匹配了字符串开始的3个字母<p>,然后是.*。点号表示匹配除换行符以外的任意字符,星号这个“贪婪”量词表示重复零次或多次,匹配尽量多的次数。因为目标字符串中没有换行符,正则表达式将匹配剩下的全部字符串!不过由于正则表达式模板中还有更多内容需要匹配,所以正则表达式尝试匹配<。由于在字符串末尾匹配不成功,因此每次回溯一个字符,继续尝试匹配<,直到正则表达式回到</div>标签的<位置。接下来尝试匹配\/(转义反斜杠),匹配成功,然后匹配p,匹配不成功。正则表达式继续回溯,重复此过程,直到第二段末尾时终于匹配了</p>。匹配返回成功需要从第一段头部一直扫描到最后一个的末尾,这可能不是我们想要的结果。

将正则表达式中的“贪婪”量词*改为“懒惰”(又名“非贪婪”)量词*?,以匹配单个段落。“懒惰”量词的回溯工作以相反方式进行。当正则表达式/<p>.*?<\/p>/推进到.*?时,首先尝试全部跳过,然后继续匹配<\/p>。

这样做是因为*?匹配零次或多次,尽可能少重复,尽可能少意味着可以重复零次。但是,当随后的<在字符串的这一点上匹配失败时,正则表达式回溯并尝试下一个最小的字符数:1个。正则表达式继续像这样向前回溯到第一段的末尾,在那里量词后面的<\/p>得到完全匹配。

如果目标字符串只有一个段落,那么此正则表达式的“贪婪”版本和“懒惰”版本是等价的,但尝试匹配的过程不同。

当一个正则表达式占用浏览器几秒甚至更长时间时,问题原因很可能是回溯失控。为说明此问题,给出下面的正则表达式,它的目标是匹配整个HTML文件。此表达式被拆分成多行是为了适合页面显示。与其他正则表达式不同,JavaScript在没有选项时可使点号匹配任意字符,包括换行符,所以此例中以[\s\S]匹配任意字符。

/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>
[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

此正则表达式匹配在正常HTML 字符串时工作良好,但当目标字符串缺少一个或多个标签时,就会变得十分糟糕。例如</html>标签缺失,最后一个[\s\S]*?将扩展到字符串的末尾,因为在那里没有发现</html>标签,然后正则表达式将查看此前的[\s\S]*?队列记录的回溯位置,使它们进一步扩大。正则表达式尝试扩展倒数第二个[\s\S]*?—用它匹配</body>标签,就是此前匹配过正则表达式模板<\/body>的那个标签,然后继续查找第二个</body>标签,直到字符串的末尾。当所有这些步骤都失败时,倒数第三个[\s\S]*?将被扩展,直至字符串的末尾,依此类推。

此类问题的解决办法在于尽可能具体地指出分隔符之间的字符匹配形式,如模板“.*?”用于匹配双引号包围的一个字符串。用更具体的[^"\rn]*取代过于宽泛的.*?就去除了回溯时可能发生的几种情况,如尝试用点号匹配引号,或者扩展搜索超出预期范围。

在HTML 的例子中解决办法不是那么简单。不能使用否定字符类型,如用[^<]替代[\s\S],因为在搜索过程中可能会遇到其他类型的标签。但是,可以通过重复一个非捕获组来达到同样效果,它包含一个回溯(阻塞下一个所需的标签)和[\s\S](任意字符)元序列。这样可以确保中间位置上查找的每个标签都会失败。然后,更重要的是,[\s\S]模板在回溯过程中阻塞的标签在被发现之前不能被扩展。应用此方法后对正则表达式的最终修改如下:

/<html>(?:(?!<head>)[\s\S])*<head>(?:(?!<title>)[\s\S])*<title>

(?:(?!<\/title>)[\s\S])*<\/title>(?:(?!<\/head>)[\s\S])*<\/head>

(?:(?!<body>)[\s\S])*<body>(?:(?!<\/body>)[\s\S])*<\/body>
(?:(?!<\/html>)[\s\S])*<\/html>/

虽然这样做消除了潜在的回溯失控,并允许正则表达式在匹配不完整HTML字符串失败时的使用时间与文本长度呈线性关系,但是正则表达式的效率并没有提高。像这样为每个匹配字符进行多次前瞻,缺乏效率,而且成功匹配过程也相当慢。匹配较短字符串时使用此方法相当不错,而匹配一个HTML 文件可能需要前瞻并测试上千次。


# 正则表达式  # 回溯  # 正则表达式之回溯  # PHP正则表达式的效率 回溯与固化分组  # 小议正则表达式效率 贪婪、非贪婪与回溯  # PHP 正则表达式效率 贪婪、非贪婪与回溯分析(推荐)  # 正则表达式学习教程之回溯引用backreference详解  # 正则表达式之分组的回溯引用问题  # 如何防止JavaScript中的正则表达式回溯  # 浅谈正则表达式回溯陷阱  # 第二个  # 这一  # 配了  # 第一个  # 在那里  # 这样做  # 换行符  # 解决办法  # 不成功  # 到第  # 过程中  # 此前  # 的是  # 是一个  # 就会  # 还没有  # 是因为  # 多个  # 依此类推 


相关文章: 魔毅自助建站系统:模板定制与SEO优化一键生成指南  如何快速搭建虚拟主机网站?新手必看指南  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  jQuery 常见小例汇总  贸易公司网站制作流程,出口贸易网站设计怎么做?  浙江网站制作公司有哪些,浙江栢塑信息技术有限公司定制网站做的怎么样?  网站制作大概多少钱一个,做一个平台网站大概多少钱?  网站制作的方法有哪些,如何将自己制作的网站发布到网上?  高性能网站服务器部署指南:稳定运行与安全配置优化方案  宝塔新建站点报错如何解决?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  建站主机与服务器功能差异如何区分?  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  大连网站制作公司哪家好一点,大连买房网站哪个好?  建站之星伪静态规则如何正确配置?  PHP正则匹配日期和时间(时间戳转换)的实例代码  如何登录建站主机?访问步骤全解析  建站之星如何一键生成手机站?  如何通过可视化优化提升建站效果?  建站主机是什么?如何选择适合的建站主机?  如何高效生成建站之星成品网站源码?  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?  如何在Windows虚拟主机上快速搭建网站?  表情包在线制作网站免费,表情包怎么弄?  网站制作知乎推荐,想做自己的网站用什么工具比较好?  建站之星如何实现网站加密操作?  如何快速重置建站主机并恢复默认配置?  制作网站公司那家好,网络公司是做什么的?  建站之星安装失败:服务器环境不兼容?  宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  建站主机与虚拟主机有何区别?如何选择最优方案?  网站制作服务平台,有什么网站可以发布本地服务信息?  淘宝制作网站有哪些,淘宝网官网主页?  如何确保西部建站助手FTP传输的安全性?  建站之星安装需要哪些步骤及注意事项?  昆明网站制作哪家好,昆明公租房申请网上登录入口?  深圳企业网站制作设计,在深圳如何网上全流程注册公司?  建站之星与建站宝盒如何选择最佳方案?  建站主机选虚拟主机还是云服务器更好?  宝塔Windows建站如何避免显示默认IIS页面?  保定网站制作方案定制,保定招聘的渠道有哪些?找工作的人一般都去哪里看招聘信息?  如何在Windows 2008云服务器安全搭建网站?  北京网站制作网页,网站升级改版需要多久?  如何在云主机上快速搭建网站?  如何快速配置高效服务器建站软件?  高防服务器:AI智能防御DDoS攻击与数据安全保障  天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?  如何选择高效可靠的多用户建站源码资源?  建站之星图片链接生成指南:自助建站与智能设计教程 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。