JavaScript regex exec执行时间太长

时间:2009-07-09 03:17:53

标签: javascript regex internet-explorer firefox browser

我有一个简单的JavaScript正则表达式检查(由其他开发人员编写),可以完美地处理数千个不同的字符串。但是我刚发现一个特定的字符串值导致正则表达式在Firefox / IE中执行长达10分钟是不可接受的。为方便起见,我已将实际的正则表达式调用解压缩为小代码段:

<html>
  <script>
    function dodo(){
      var mask = /^([\w'#@\-\&\(\)\/.]+[ ]*){1,100}$/;
      var value = "Optometrists Association Australia, Queensland/NT Division";
      mask.exec(value);
    }
  </script>
  <body>
    <input type="button" value="Click" onclick="dodo()">
  </body>
</html>

这是什么问题?如果我将值改为其他任何东西,它就能完美地运作。

谢谢!

4 个答案:

答案 0 :(得分:6)

你可能意味着在空间组之后有一个+,而不是*。如果用+替换它,事情就会快得多。 *会导致正则表达式评估程序尝试大量的组合,所有这些组合在到达','时都会失败。您可能还想在第一个字符组中添加“,”。

总体而言,它可能如下所示:

var mask = /^([\w'#@\-\&\(\)\/.,]+[ ]+){1,100}$/;

答案 1 :(得分:6)

你正在进行疯狂的回溯,这是正则表达式中的一个常见功能,包括一些形式([字符] +)+ - 它适用于各种匹配模式,但是你会发现像这样的字符串,它使它爆炸,在整个字符串递归。这是一个发生了什么的草图。

首先,您的模式将字符串拆分为组。我使用|来启动您的群组实例,即您重复的群组{1,100}>是组的结尾,?是正则表达式解析器的“游标”。

|----------->|---------->|-------?
Optometrists Association Australia, Queensland/NT Division

在?处,您的模式无法再匹配任何符号或空格,因此它会尝试匹配$。由于光标尚未到达行的末尾,因此它失败,正则表达式解析器回溯:

|----------->|---------->|------?
Optometrists Association Australia, Queensland/NT Division

再一次,它找不到任何空格,因此终止该组,并尝试启动另一个(因为最多可以有100个,到目前为止我们只使用了3个。)

|----------->|---------->|------|-?
Optometrists Association Australia, Queensland/NT Division

解析器再次遇到有问题的,,它会杀死该执行树,导致它再次回溯到i中的Australia。而且,就像上次一样,它试图创建一个小组:

|----------->|---------->|-----|--?
Optometrists Association Australia, Queensland/NT Division

...无论如何,你明白了。这个循环的失败,回溯和切片将再次有效地冻结你的正则表达式解析器,直到每个排列耗尽并返回false。识别和解决这个问题的关键是永远不要重复一个重复的组,在开头和/或结尾没有某种形式的分隔符。我建议使用边界锚\b这个词,因为[ ]+会要求你的字符串以空格结尾:

/^(\b[\w'#@\-\&\(\)\/.]+\b[ ]*){1,100}$/

作为旁注,如果没有更多的上下文,很难说你的正则表达式在做什么,但似乎你也可以调用value.split(' ')将字符串拆分为空格字符,并运行更简单的正则表达式所有这些子串。它消除了对双重正则表达式重复的需要。

答案 2 :(得分:4)

这看起来像一个正则表达式的糟糕应用程序,以及一个糟糕的正则表达式启动。我认为,目的似乎是匹配1到100个以空格分隔的“单词”的列表。以下是我可以看到的核心问题:

  1. 在单词的末尾使用“[] *”而不是“[] +”意味着每个字节都可能只是一个“单词”,无论它是否以空格为界。这是你的引擎跟踪的很多匹配案例。

  2. 您正在使用捕获括号(“(...)”)而非捕获括号(“(?:...)”)。分组将更多地保存,以保存与您匹配的最后一个单词,您可能需要或不需要。

  3. 还有一些小问题:

    1. “[] *”表达式是多余的。只需使用“*”匹配零个或多个空格即可。但是你可能想要“\ s”来匹配任何类型的空格,而不仅仅是空格。

    2. 表达式允许字符串末尾的空格,但不允许开头。大多数应用程序通常都希望容忍这两种应用程序,或者两者都不容忍。

    3. 为了便于阅读,请勿在不需要的地方使用反斜杠转义。只有括号中的“ - ”才需要它。

    4. 100的魔力是什么?你真的想要硬编码这个限制吗?

    5. 最后,为什么要在这里使用正则表达式?为什么不简单地将空格上的split()转换为子串数组,然后针对更简单的表达式测试每个结果单词?

答案 3 :(得分:1)

从字符串中删除逗号或将其添加到字符组会使其快速执行,但如果没有正确操作的示例或对您要实现的内容的解释,我无法确定它是否正常工作。 ..