我正在调试一个应用程序中的问题,该应用程序使用正则表达式验证客户端的电子邮件(是的,我知道,两者都有点愚蠢)并且问题让我感到非常难过。
问题是验证在Chrome中运行得很好但在Firefox中失败了,我想知道它是否是一个错误,或者正则表达式是否有错误导致错误。
请查看此小提琴,了解完整的测试用例:http://jsfiddle.net/KQvgJ/
new RegExp(/^\S+([\_\-\.]*\S+[\_\-]?)*@\S+([\_\-]?\S+)*\.+([\-\_]?\S)+(\.?\S+)*$/);
在Firefox中,只有上面的正则表达式匹配mw@thisissometest.de
而不是mw@thisissometestbutlong.de
。
似乎单独根据输入的长度而失败,但表达式中根本没有长度限制!?
答案 0 :(得分:3)
首先,让我们明确\S+
将匹配任何不是空格的内容一次或多次。
^\S+([\_\-\.]*\S+[\_\-]?)*@\S+([\_\-]?\S+)*\.+([\-\_]?\S)+(\.?\S+)*$
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^
This all get's matched Same here wut? Same here, just
with \S+, so we can repeat use \S+
drop it dots?
所以我们可以通过使用\S+@\S+\.\S+
来简化它,但是等一下?如果是这样的话,我们可以使用非感性的\S+
。我们使用^[^\s@]+@[^\s@]+$
。
^
:行首[^\s@]+
:匹配除空格和@
@
:匹配@
[^\s@]+
:匹配除空格和@
$
:行尾让我们修复你的正则表达式。请注意,在字符类中,您不需要转义点,下划线等...将连字符放在开头,您也不需要将其转义。在此之后,让我们删除\.+
中那个丑陋的量词,结果如下:
^\S+([-_.]*\S+[-_]?)*@\S+([-_]?\S+)*\.([-_]?\S)+(\.?\S+)*$/
现在通过消除正则表达式的某些部分,我找到了罪魁祸首。这是\S+
:
^\S+([-_.]*\S+[-_]?)*@\S+([-_]?\S+)*\.([-_]?\S)+(\.?\S+)*$
here --^
所以你的最终正则表达式应该是^\S+[-_.]*@\S+([-_]?\S+)*\.([-_]?\S)+(\.?\S+)*$
See it working !
现在,如果你问我为什么?我老实说不知道,但我一如既往地推荐阅读以下文章:Stop Validating Email Addresses With Complicated Regular Expressions。
答案 1 :(得分:2)
错误肯定在你的正则表达式中:它在病理上效率低下。基本上,您有多个可以匹配相同字符的连续部分,全部由开放式量词(*
和+
)控制。这创造了正则表达式在放弃匹配之前必须检查的天文数量的“路径”。事实上,只有当不可能匹配时,这种问题才会变得明显,但是你已经设法在 匹配的正则表达式上触发它。
我怀疑你正在尝试这样的事情:
/^[a-z]+(?:[_.-][a-z]+)*@[a-z]+(?:\.[a-z]+)*$/i
在任何人开始批评之前,我知道[a-z]+
不比\S+
更正确。我只想解释他的正则表达式有什么问题。我们的想法是强制用户名和域名以字母开头,同时允许它们分成围绕分隔符的块,如.
,-
和_
。这就是它如此复杂的原因
这个正则表达式最重要的特征是它始终向前发展。当[a-z]+
耗尽要使用的字母时,它看到的下一件事必须是分隔字符之一,符号('@')或字符串的结尾(取决于匹配的地址部分)。如果它没有看到它的期望,则匹配尝试立即失败。
在你的正则表达式中,\S+
部分最初吞噬整个字符串,然后开始一次退出一个字符,为下一个部分提供匹配的机会。每个\S+
重复此过程。正如HamZa观察到的那样,这就是正则表达式引擎花费大部分时间的地方。但不仅仅\S+
会杀死你,而是正则表达式的结构。