字符串正则表达式用户名或电子邮件挂起

时间:2014-06-03 08:13:58

标签: javascript jquery regex

验证用户名输入字段时出现问题。

正则表达式:

var mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$/;
var letterNumber = /^[0-9a-zA-Z]*$/;

支票:

if (!letterNumber.test($('#login_username').val()) 
      && !mailformat.test($('#login_username').val())){
 ...
}

当我想通过此条目验证时,浏览器(chrome和ie)会挂起:

012345678901234567890123456789@

任何人都知道为什么?

我在一个表达式中尝试使用正则表达式,但得到了相同的结果。 (正则表达式是可以的,因为他们分开工作)

2 个答案:

答案 0 :(得分:5)

你偶然发现了catastrophic backtracking

要修复它,您可以使用:

^\w+([.-]\w+)*@\w+([.-]\w+)*(\.\w{2,4})+$

在声明匹配失败之前,正则表达式引擎必须检查应用正则表达式的所有可能方法。

使用\w+([.-]?\w+)*,每个数字可以由\w+([.-]?\w+)*匹配,失败时([.-]?\w+)*的行为与(\w+)*相同。这创建了一个很多状态来回归。

强制使用[.-]会消除这种歧义。


开启(灾难性)回溯

正则表达式引擎的工作方式是它在正则表达式中移动,尝试将它的每个部分与字符串相匹配。每次它有一个选择,它会保存状态,以便它可以回溯到它,如果这是错误的路径。

为了说明,请参阅.*babc的匹配方式。

  • .*量词是贪婪的,所以它会尽可能匹配:它首先匹配任何内容,然后添加a,然后添加b,然后添加{{ 1}}。每次引擎记住它时,选择来添加另一个角色。然后引擎会尝试匹配c,但我们会在字符串的末尾进行匹配,以便失败。

  • 没什么大不了的,我们回到最后的选择:现在b只匹配.*。最终的ab仍然与字符串结尾b不匹配。

  • 我们更进一步:c匹配.*a最终可以匹配。总体匹配项找到:b

在了解正则表达式与输入不匹配之前,引擎必须尝试所有这些替代方案。如果允许字符与正则表达式的多个部分匹配,则该数字会增加。

在你的情况下,它随着字符串的长度呈指数增长,直到返回任何东西都是永远的:这是灾难性的回溯。

Friedl关于这个主题的精彩插图:http://www.foo.be/docs/tpj/issues/vol1_2/tpj0102-0006.html

答案 1 :(得分:2)

因为这里发生了灾难性的回溯。正则表达式中的大多数术语

`^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,4})+$`

几乎匹配测试字符串的全长

`012345678901234567890123456789@`

然后它必须回溯,因为没有发生完全匹配。

enter image description here

例如。 ^\w+匹配 012345678901234567890123456789 @ ^\w+([\.-]?\w+)*,最终^\w+([\.-]?\w+)*@匹配完整的字符串 现在有@之后的单词即可。正则表达式中^\w+([\.-]?\w+)*@\w+因此它必须回溯并找到前一部分的合适匹配,即。 ^\w+([\.-]?\w+)*@再一次,这个回溯过程一直持续到找到匹配为止。