Java 模式匹配时的冻结

Java 模式匹配时的冻结,java,regex,Java,Regex,我的程序遇到了一个小问题。它似乎冻结了,很可能是由while循环引起的 我试图做的是提取并替换Java注释。因此,在键入块注释时,您将使用/*打开该注释。如果没有结束(*/),程序冻结时需要5-6秒,您无法使用它。我已经用更多的正则表达式和超过10000行的文件运行了这个过程,没有任何性能问题,因此任何类型的性能下降都是令人震惊的,但仅仅是5秒的延迟 private static final String COMMENT_MATCHER = "(//.*)|(/\\u002A((\\s)|(.)

我的程序遇到了一个小问题。它似乎冻结了,很可能是由while循环引起的

我试图做的是提取并替换Java注释。因此,在键入块注释时,您将使用
/*
打开该注释。如果没有结束(
*/
),程序冻结时需要5-6秒,您无法使用它。我已经用更多的正则表达式和超过10000行的文件运行了这个过程,没有任何性能问题,因此任何类型的性能下降都是令人震惊的,但仅仅是5秒的延迟

private static final String COMMENT_MATCHER = "(//.*)|(/\\u002A((\\s)|(.))*?\\u002A/)";

private String clearMatches(String code, final String regex) {
    final Pattern pattern = Pattern.compile(regex);
    final Matcher matcher = pattern.matcher(code);
    while (matcher.find()) {
        final String match = matcher.group();
        code = code.replace(match, CharBuffer.allocate(match.length()).toString());
    }
    return code;
}
我猜问题在于找到许多匹配项并遍历所有匹配项,因为有一个星号


你好,欧比切丽。

你对时间的观察并不令人惊讶。由于回溯,Java regexp匹配可能非常慢(即,如果n是regexp的长度,则为O(2**n))。有时可以修改regexp以避免回溯,因此它会变得很快

一种加速方法是使用所有格量词,请参见。另一种加速方法是使用更少的
|
操作符

试试这个:

private static final String COMMENT_MATCHER = "(//.*+)|(?s)(/[*].*?[*]/)";
COMMENT_MATCHER = "//[^\r\n]*+|/[*](?:(?![*]/)[\\s\\S])*+[*]/";
试试这个:

private static final String COMMENT_MATCHER = "(//.*+)|(?s)(/[*].*?[*]/)";
COMMENT_MATCHER = "//[^\r\n]*+|/[*](?:(?![*]/)[\\s\\S])*+[*]/";
它应该运行得更快

模式的快速分解:

// # match "//" [^\r\n]*+ # possessively match any chars other than line break chars | # OR /[*] # match "/*" (?: # start non-capture group (?![*]/)[\\s\\S] # match any char, only if "*/" is not ahead )*+ # end non-capture group and possessively repeat zero or more times [*]/ # match "*/" //#匹配“/” [^\r\n]*+#占有式匹配除换行符以外的任何字符 |#或 /[*]#匹配“/” (?:#启动非捕获组 (?![*]/)[\\s\\s]#仅当“*/”不在前面时匹配任何字符 )*+#结束非捕获组并占有重复零次或多次 [*]/#匹配“*/”
我相信您可以通过使用两种方法来帮助调试—一种用于多行注释,另一种用于单行注释。例如,有两个常量
SINGLE_-LINE_-COMMENT_-MATCHER
MULTI_-LINE_-COMMENT_-MATCHER
,每个常量都有自己的正则表达式。@Meesh MATCHER匹配注释很好,就在多行注释没有结尾的时候。当你输入它们时,你会遇到这种情况。你的模式可以简化为更可读的(至少对我来说)版本
“//[^\n]*.[*].?[*]/”
,如果你在开始时使用
模式.DOTALL
标记或添加
(?s)
,哇,它成功了!我不是Regex的高手,我也不知道,谢谢。