首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议44:正确使用原子组

关灯直达底部

正则表达式引擎支持一种称做原子组的属性。原子组写作(?>…),也称为“贪婪”子表达式,省略号表示任意正则表达式模板、非捕获组和一个特殊的扭曲。存在于原子组中的正则表达式组中的任何回溯点都将被丢弃。这就为HTML正则表达式的回溯问题提供了一个更好的解决办法:如果将[/s/S]*?序列和它后面的HTML标记一起放在一个原子组中,所需的HTML标签被发现一次,这次匹配基本上就被锁定了。如果正则表达式的后续部分匹配失败,原子组中的量词没有记录回溯点,那么[/s/S]*?序列就不能扩展到已匹配的范围之外。

但是,JavaScript不支持原子组,也不提供其他方法消除不必要的回溯。不过,可以利用前瞻过程中一项鲜为人知的行为来模拟原子组:前瞻也是原子组。不同的是,前瞻在整个匹配过程中不消耗字符,前瞻只是检查自己包含的模板是否能在当前位置匹配。然而,可以避开这点,在捕获组中包装一个前瞻模板,在前瞻之外向它添加一个后向引用。


(?=(pattern to make atomic))/1


在任何使用原子组的模式中这个结构都是可重用的。只要记住,需要使用适当的后向引用次数,如果正则表达式包含多个捕获组。HTML正则表达式在使用此技术后的修改如下:


/<html>(?=([/s/S]*?<head>))/1(?=([/s/S]*?<title>))/2(?=([/s/S]*?

<//title>))/3(?=([/s/S]*?<//head>))/4(?=([/s/S]*?<body>))/5

(?=([/s/S]*?<//body>))/6[/s/S]*?<//html>/


如果没有尾随的</html>,那么最后一个[/s/S]*?将扩展至字符串结束,正则表达式将立刻失败,因为没有回溯点可以返回。正则表达式每次找到一个中间标签就退出一个前瞻,它在前瞻过程中丢弃所有回溯位置。下一个后向引用简单地重新匹配前瞻过程中发现的字符,将它们作为实际匹配的一部分。