有没有办法优化这种灾难性正则表达式回溯的情况?

时间:2019-04-16 08:32:49

标签: regex performance

所以我想出了以下正则表达式:

([^\s\\]+(?:\\.[^\s\\]*)*)(?:.*?)(\S+\.php\b)

测试链接:https://regex101.com/r/NV6Bk4/4

它与命令行的二进制名称和脚本名称匹配。示例:

php --strict myscript.php --arg=value

匹配组(1)和组(2)中的phpmyscript.php

问题是中间的这一部分:(?:.*?),它导致组合爆炸,从而减慢了大输入量的正则表达式。有没有一种方法可以对此进行优化?既然没有模式,我什么都想不起来。

为了澄清,我要匹配的规则是: 将任何路径匹配到命令,可能包含转义的空格。忽略其后的所有参数。匹配以.php结尾的文件,忽略其后的所有内容。该命令应该在组(1)中,文件名应该在组(2)中。

1 个答案:

答案 0 :(得分:1)

您可以在Matcher#matches()中使用以下“修复程序”:

([^\s\\]*+(?:\\.[^\s\\]*)*).*?(\S+\.php\b).*

在Java中

String regex = "([^\\s\\\\]*+(?:\\\\.[^\\s\\\\]*)*).*?(\\S+\\.php\\b).*";

请参见regex demo。请注意,字符类外部的文字.必须转义。如果字符串可能有换行符,请使用Pattern.DOTALL编译模式。

如您所见,.*?部分匹配任何字符,并且(?:\\.[^\s\\]*)*可以匹配任何0个或更多字符(因此,它是可选的),以及{{左侧的1}}是.*?,可以与[^\s\\]+匹配相同的字符。这意味着,正则表达式引擎可能会回溯到第一个子模式,从而创建了许多匹配字符串的方法,通常称为灾难性回溯。

如果您不允许使用.*?所有格量词回溯到第一个否定字符类,它将已经更加可靠了。

在末尾添加*+,使其与.*一起使用,因为此方法需要完整的字符串匹配。