什么可能导致node.js中这种奇怪的正则表达式行为?

时间:2013-09-15 23:35:34

标签: regex node.js v8

执行以下代码,需要永远:

"Hello there, very best wishes, from Syria...".match(/^((?:, |[\w ]+)+)$/)

在执行以下操作时,比以往任何时候都要少一点,但是超过十秒钟!

"Hello there, best wishes, from Syria...".match(/^((?:, |[\w ]+)+)$/)

...然后返回null

试用我的Ubuntu 12.04 64位计算机,Archlinux 32位服务器和Debian Wheezy 32位服务器,所有服务器都运行节点v0.10.18。


编辑:显然行为是从V8继承的,相同的代码会让Chrome的控制台挂起,而mongo shell(也使用V8)也会挂起!

2 个答案:

答案 0 :(得分:1)

这个正则表达式是等价的并且运行得很快:

/^([\w, ]+)$/

问题在于你的正则表达式,而不是V8。其他引擎在尝试一段时间之后只报告不匹配(这不一定是正确的结果),V8尝试获得正确的结果,即使它需要永远。你需要注意你如何编写正则表达式,它就像任何其他代码一样 - 它不会神奇地防止程序员的错误。

答案 1 :(得分:1)

我很确定这里发生的事情是catastrophic backtracking。例如在我的机器上:

  • 对于“Hello there, best wishes, from Syria...”中的39个字符,大约需要13-14秒。
  • 对于“Hello there, vbest wishes, from Syria...”中的40个字符,需要27-28秒。
  • 对于“Hello there, vebest wishes, from Syria...”中的41个字符,需要56秒。

您可以看到所花费的时间呈指数级增长。为了解释正则表达式引擎如何通过回溯来匹配字符串,我将引用上面链接中的示例。它在字符串(x+x+)+y上应用正则表达式xxxxxxxxxxy

  

让我们看看将此正则表达式应用于xxxxxxxxxxy时会发生什么。该   第一个x +将匹配所有10个x字符。第二个x +失败了。该   先x +然后回溯到9场比赛,第二场比赛拿到了   剩下的x。该组现已匹配一次。该组重复,但   在第一个x +失败。由于一次重复就足够了,小组   火柴。 y匹配y并找到整体匹配。正则表达式是   声明功能,代码发送给客户,他的   电脑爆炸。几乎。

     

当主题中缺少y时,上述正则表达式变得难看   串。当y失败时,正则表达式引擎会回溯。该小组有一个   迭代它可以回溯到。第二个x +只匹配一个x,所以   它不能回溯。但是第一个x +可以放弃一个x。第二个x +   及时匹配xx。该组再次进行一次迭代,下一次失败   一个,而y失败了。再次回溯,第二个x +现在有一个   回溯位置,减少自身以匹配x。小组尝试了   第二次迭代。第一个x +匹配,但第二个卡在   字符串的结尾。再次回溯,小组中的第一个x +   第一次迭代将自身减少到7个字符。第二个x +匹配   XXX。如果失败,则第二个x +减少到xx,然后减少到x。现在   group可以匹配第二次迭代,每个x +只有一个x。但是这个   (7,1),(1,1)组合也失败了。所以它转到(6,4)然后   (6,2)(1,1)然后(6,1),(2,1)然后(6,1),(1,2)然后我认为   你开始得到漂移。

请参阅杰夫关于正则表达式性能的this页面,该页面使用相同的示例。所以道德故事:不要只匹配东西,改善正则表达式。嵌套重复运算符时,请确保只有一种方法可以匹配相同的匹配。对于我引用xx+y的示例,效果更好。对于你的正则表达式,Esailija给出的答案会更好/^([\w, ]+)$/