例如,查看此电子邮件验证正则表达式:
^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$
。如果仔细观察,有三个部分:东西,@
字符和更多东西。因此,正则表达式要求电子邮件地址为@
,因此字符串aaaaaaaaaaaaaaaaaaaaaa!
将不匹配。
然而,鉴于这种组合,大多数正则表达式engine将会灾难性地回溯。 (PCRE,它为Regex101提供动力,比大多数人聪明,但其他正则表达式/字符串组合可能导致灾难性的回溯。)
无需了解Big O,我可以看出组合事物是指数级的,而搜索是线性的。那么为什么不使用正则表达式引擎确保字符串包含必需的字符(这样它们可以提前退出)?
不幸的是,我所读到的关于灾难性回溯的大部分内容都将正则表达式编写者归咎于编写恶意正则表达式,而不是探索正则表达式引擎/编译器需要做得更好的可能性。虽然我发现了几个关注正则表达式引擎/编译器的source,但它们太技术化了。
在获得更多经验后回来,我知道正则表达式是declarative,这意味着执行计划由计算机决定,而不是由程序员决定。优化是正则表达式引擎差异最大的方法之一。
虽然PCRE和Perl通过引入回溯控制动词来挑战声明性状态,但是其他引擎,没有动词,最有可能发生灾难性的回溯。
答案 0 :(得分:4)
我认为你采取了错误的方式,真的:
不幸的是,我读到的关于灾难性回溯的大部分内容都将正则表达式编写者归咎于编写恶意正则表达式,而不是探索正则表达式引擎/编译器需要做得更好的可能性。虽然我发现了几个关注正则表达式引擎/编译器的资料,但它们太技术化了。
好吧,如果你写一个正则表达式,你的正则表达式引擎将需要遵循你编写的程序。
如果你编写一个复杂的程序,那么引擎就无法做到这一点;此正则表达式明确指定在查找@
之前,您需要首先匹配“stuff”。
现在,我不同意编写编译器,我同意,在这种情况下,有可能首先识别所有“静态”元素,这里只说@
,并寻找它们。可悲的是,在一般情况下,这对你来说并没有真正的帮助,因为可能有多个静态元素或者根本没有...
如果你关心速度,你实际上只是首先用简单的线性搜索搜索@
,然后在你找到它之后再做你的正则表达式。
正则表达式从来没有像线性搜索引擎一样快,因为它们意味着更强大,更强大。
所以,你不仅要把错误的人带到法官身上(正则表达式引擎而不是正则表达式,这是一个复杂的程序),你还要指责受害者犯罪(你想收获只是寻找@
字符的速度,但仍使用正则表达式。
<小时/> 顺便说一句,不要使用正则表达式验证电子邮件地址。这是错误的工具: http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html