为什么Regex IsMatch()会挂起
我有一个exressression来validation电子邮件地址:
string REGEX_EMAIL = @"^\w+([\.\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\¦\}\~]*\w+)*@\w+([\.\-]\w+)*\.\w+([\.\-]\w+)*$";
如果地址正确,IsMatch()方法会快速显示真实结果。 但是如果地址字符串很长且错误,则此方法会挂起。
我该怎么做才能提高这种方法的速度?
谢谢。
你有几件事正在影响这个正则表达式的表现。
- 灾难性的回溯
- 可选语句太多
你可以通过在几个关键位置使用+
而不是*
来提高性能,但这当然会改变正则表达式将匹配和不匹配的内容。 因此,我发现的最简单的修复实际上涵盖在上面的灾难性回溯文章中。 在这种情况下,您可以使用nonbacktracking子表达式来显着提高性能,而无需以任何重要的方式更改正则表达式的行为。
nonbacktracking子表达式看起来像这样…… (?>pattern)
所以试试这个正则表达式:
^\w+(?>[\.\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\¦\}\~]*\w+)*@\w+([\.\-]\w+)*\.\w+([\.\-]\w+)*$
在一个稍微相关的主题上,我检查有效电子邮件地址的理念有点不同。 例如,像你这样的长正则表达式可能会出现性能问题。
其次,电子邮件地址国际化即将到来,这使得所有这些更加复杂化。
最后,任何基于正则表达式的电子邮件validation的主要目的是捕获拼写错误和公然尝试通过您的表单而不输入真实的电子邮件地址。 但要检查电子邮件地址是否为正版,则需要向该地址发送电子邮件。
所以我的理念是错误接受太多。 事实上,这是一件非常简单的事情……
^.+@.+\..+$
这应该匹配任何可以想象的有效电子邮件地址,以及一些无效的电子邮件地址。
您正在经历灾难性的回溯 。
简化的正则表达式:
Regex regexObj = new Regex(@"^\w+([-.!#$%&'*+/=?^`{¦}~]*\w+)*@\w+([.-]\w+)*\.\w+([.-]\w+)*$");
有潜在的问题,例如([.-]\w+)*\.
如果.
例如,缺少一个很长的字符串然后必须考虑所有可能的组合,以便你的正则表达式找出它实际上失败了。
所以,有一些回溯问题。 您可以通过谨慎使用独立子表达式构造来减少这些问题,但是您仍然会遇到问题,因为内部表达式不具有该约束。 最好的办法是分离主要部分。
将其更改为有助于(扩展):
^ (?> \w+ ( [\.\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\¦\}\~]* \w+ )* @ \w+ ) (?> ([\.\-]\w+)* \. \w+ ([\.\-]\w+)* ) $
但是,如果通过放置一些放置好的断言来重构等效表达式,然后重新添加独立的子表达式分组,则可以实际上消除回溯。 通过我的正则表达式dubugger运行它表明它只需要很少的步骤来传递或失败(扩展):
^ (?> \w+ [\.\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\¦\}\~\w]* (?<=\w) @ \w+ ) (?=.*\.\w) (?> ([\.\-]\w+)+ ) $