为了账号安全,请及时绑定邮箱和手机立即绑定

Javascript正则表达式挂起(使用v8)

/ 猿问

Javascript正则表达式挂起(使用v8)

Javascript正则表达式挂起(使用v8)

我正在使用此正则表达式来获取文件中的标记内容。

var regex = new RegExp("<tag:main>((?:.|\\s)*)</tag:main>");

这会导致v8引擎无限期挂起。

现在,如果我使用new RegExp("<tag:main>([\s\S]*)</tag:main>"),一切都很好。

任何人都知道为什么第一个需要太长时间?


查看完整描述

3 回答

?
慕雪9262066

这会灾难性地回溯在最后一个结束</tag:main>标记之后出现的长序列空间。考虑主题字符串以100个空格结尾的情况。首先,它将它们全部与.交替的左侧相匹配。这失败了,因为没有结束标记,所以它尝试匹配最后一个字符\s。这也失败了,所以它尝试匹配倒数第二个空格作为a \s和最后一个空格作为a .。失败(仍然没有结束标记)所以它尝试最后一个空格作为\s。当失败时它将第三个到最后一个空格匹配为a \s并尝试所有4种方式来匹配最后两个空格。当失败时,它会尝试倒数第四个空格\s以及最后3个空格中的所有8种方式。然后是16,32等。宇宙在它到达第100个到最后的空间之前结束。

由于灾难性的回溯,不同的VM对regexp匹配的反应不同。有些人只会报告“不匹配”。在V8中,它就像编写任何其他无限或近无限循环一样。

使用非贪婪*会做你想要的(你想要在第一个</tag:main>而不是最后一个停止),但仍会对缺少关闭序列的长串空间进行灾难性的回溯。

确保内括号中的相同字符不能与交替的两侧匹配将减少从指数一到一的问题,该问题在字符串的长度上是线性的。使用字符类而不是替换或放在\n交替栏的右侧。 如果您按下一长串空格,则正则表达式引擎在终止之前不会尝试所有左右 - 左等组合\n.因此是不相交的。


查看完整回答
反对 回复 2019-08-28
?
阿波罗的战车

我认为这是灾难性的追溯。

我认为问题的一部分可能是dot和\ s不是互斥的。

如果我改变你的表达方式

<tag:main>((?:.|[\r\n])*)</tag:main>

并在Regex Buddy调试器中运行它,如果测试字符串不匹配,它会更快地失败。


查看完整回答
反对 回复 2019-08-28
?
冉冉说

(?:.|\s)*您可以使用[^]*匹配任何字符(包括各种形式的换行符)来代替。

没有交替,所以没有灾难性回溯的风险。


查看完整回答
反对 回复 2019-08-28

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信