Java Matcher慢速正则表达式



这是一个非常简单的正则表达式,它在一个非常短的字符串上运行超过30秒:(i7 3970k @ 3.4ghz

Pattern compile = Pattern.compile("^(?=[a-z0-9-]{1,63})([a-z0-9]+[-]{0,1}){1,63}[a-z0-9]{1}$");
Matcher matcher = compile.matcher("test-metareg-rw40lntknahvpseba32cßáàâåäæç.nl");
boolean matches = matcher.matches(); //Takes 30+ seconds

第一部分(?=)是断言字符串最多包含以下字符

第二部分是断言字符串不超过语法,例如在这种情况下,以防止--s,并至少在[a-z0-9]中结束

我试着猜测你的意图,但并不容易:

(?=[a-z0-9-]{1,63})这种展望似乎打算要求接下来的63个字符是小写ASCII字母或数字,但事实上,即使只有一个字母后面跟着任何东西,它也会成功。所以,也许你的意思是(?=[a-z0-9-]{1,63}$)禁止在最多63个合法字符之后的任何其他内容。

您似乎希望-之间至少有一个字母或数字的组,但您将-设置为可选,这并没有真正创建约束,并允许使用许多可能的方法,这会造成表达式的开销。你可以简单地说:([a-z0-9]++-){0,63}[a-z0-9]+。大括号内的组至少需要一个字母或数字,并且需要减号。之后,末尾的表达式至少需要表达式末尾的一个字母和数字,但同时也将匹配最后一个没有以下-的组。如果文本中根本不包含-,那么最后一组可能也是唯一一组。

把所有这些放在一起,regex就变成了:(?=[a-z0-9-]{1,63}$)([a-z0-9]++-){0,63}[a-z0-9]+。请注意,如果使用matches方法,则不需要前导^或尾随$;它已经暗示了字符串边界必须与表达式边界匹配。

我希望我理解你的意思…

我修复了这个正则表达式,如下所示替换它:

^(?=[a-z0-9-]{1,63})([a-z0-9]{0,1}|[-]{0,1}){1,63}[a-z0-9]{1}$

部分([a-z0-9]+[-]{0,1}){1,63}变为:([a-z0-9]{0,1}|[-]{0,1}){1,63}

  • 如果您想确保字符串中没有--,只需使用负向前看(?!.*--)
  • 写CCD_ 17也没有意义
  • 另一件事是,如果您想确保字符串最多有63个字符,那么在您的展望中,您需要在(?=[a-z0-9-]{1,63}$)的末尾添加$

所以也许^(?=[a-z0-9-]{1,63}$)(?!.*--)[a-z0-9-]+[a-z0-9]$

我认为根据您的说法,您的正则表达式可以简化为编辑-(为了子孙后代)在阅读@Holger的帖子后,我正在更改这一点,以修复可能发生的灾难性回溯,并加快速度,正如我的长椅所示,这可能是最快的方法。

 #  ^(?=[a-z0-9-]{1,63}$)[a-z0-9]++(?:-[a-z0-9]+)*+$
 ^                                    # BOL
 (?= [a-z0-9-]{1,63} $ )              # max 1 - 63 of these characters
 [a-z0-9]++ (?: - [a-z0-9]+ )*+       # consume the characters in this order
 $                                    # EOL

最新更新