【问题标题】:Javascript regex hangs (using v8)Javascript 正则表达式挂起(使用 v8)
【发布时间】:2011-01-25 08:35:45
【问题描述】:

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

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

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

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

有人知道为什么第一个需要太长时间吗?

【问题讨论】:

  • 正则表达式的创建挂起还是应用它?你发布的线路对我来说很好
  • 创作不会挂起,只能通过测试或匹配使用。使用长字符串
  • 你尝试过非贪婪匹配吗? var regex = new RegExp("&lt;tag:main&gt;((?:.|\\s)*?)&lt;/tag:main&gt;");。如果文档中有多个标签元素,您的正则表达式可能会导致问题。

标签: javascript regex v8


【解决方案1】:

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

没有交替,因此没有灾难性回溯的风险。

【讨论】:

    【解决方案2】:

    这会在最后一个关闭 &lt;/tag:main&gt; 标记之后出现的长空格序列上发生灾难性的回溯。考虑主题字符串以 100 个空格结尾的情况。首先,它将它们与交替左侧的. 匹配。失败是因为没有结束标签,所以它尝试将最后一个字符与\s 匹配。这也失败了,因此它尝试将倒数第二个空格匹配为\s,将最后一个空格匹配为.。失败(仍然没有结束标签)所以它尝试最后一个空格作为\s。如果失败,它会将倒数第三个空格匹配为\s,并尝试所有 4 种方法来匹配最后两个空格。如果失败,它会尝试倒数第四个空格作为\s,并在最后 3 个空格上尝试所有 8 种方式。然后是 16、32 等。宇宙在到达倒数第 100 个空间之前就结束了。

    由于灾难性的回溯,不同的虚拟机对正则表达式匹配有不同的反应。有些人会简单地报告“不匹配”。在 V8 中,这就像编写任何其他无限或接近无限的循环一样。

    使用非贪婪的* 会做你想做的事(你想停在第一个&lt;/tag:main&gt;,而不是最后一个),但仍然会对缺少结束序列的长空格字符串进行灾难性的回溯。

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

    【讨论】:

    • 很好的解释。您是否碰巧知道 dot 是否也包含 \r?
    • @Martin: 在 JavaScript 中,. 等价于 [^\r\n\u2028\u2029]
    【解决方案3】:

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

    我认为问题的一部分很可能是点和 \s 不是相互排斥的。

    如果我把你的表情改成

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

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

    【讨论】:

    • .|\s 是匹配所有字符。因为 。匹配除换行符以外的所有字符。
    • 我认为它不会那样做。我将您的正则表达式粘贴到 RegexBuddy 中,并将其评论树粘贴到我的帖子中。
    • 您应该在粘贴到 RegexBuddy 之前删除多余的 \。使用 \\ 是因为它是传递给 RegExp 构造函数的 javascript 字符串。
    • 哎呀!如果你让它变得懒惰而不是贪婪,这是否会阻止问题?
      ((?:.|\s)*?)
    • 我现在已经完全重写了我的答案!
    猜你喜欢
    • 2013-01-21
    • 2014-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多