我遇到了一个我觉得非常有趣的问题。我正在使用正则表达式对文本文件进行一些基本的解析,并且在匹配此行时它总是会冻结
ftrect 0.7031 57.0313 9.8561 55.5313 "FREIGABE \nQ09_SV01"
没有抛出异常;该程序只是挂起。我正在发布重新创建情况的程序片段;评论的是可能的标准情况,但另一个是有问题的。如果你删除\ n它有效,但这些解析过的文件来自“blackbox”系统。
我当然可以做一个解决方法,我发现它实际上已经冻结并希望有人可以解释正在发生的事情。我在JDK6u22和JDK7u21上试过......
public static Pattern FTRECT_PATTERN = Pattern.compile(
"\\s*([\\w]+)?\\:?\\s*ftrect\\s+((\\d*\\.?\\d*\\s?)+)\\s*\"?([\\w\\s\\.\\%\\/\\=]*)?\"?\\s*"
);
public static void main(String[] args) {
// Matcher m = FTRECT_PATTERN.matcher( "FOX_BACKGROUND: ftrect 46.1719 18.0556 54.8633 16.5556 \"Schicht\" " );
Matcher m = FTRECT_PATTERN.matcher( "ftrect 0.7031 57.0313 9.8561 55.5313 \"FREIGABE \\nQ09_SV01\"" );
System.out.println( m.matches() );
for (int i = 0; i <= m.groupCount(); i++) {
String string = m.group( i );
System.out.println( string );
}
}
好吧,我发现如果我将正则表达式修改为此(将\\\\
添加到最后一个组):
public static Pattern FTRECT_PATTERN = Pattern.compile(
"\\s*([\\w]+)?\\:?\\s*ftrect\\s+((\\d*\\.?\\d*\\s?)+)\\s*\"?([\\w\\\\\\s\\.\\%\\/\\=]*)?\"?\\s*"
);
我仍然不知道为什么没有抛出异常。
答案 0 :(得分:9)
这是因为catastrophic backtracking。您的测试字符串包含一个与字符类"...\\n..."
不匹配的文字反斜杠(在[\w\s\.\%\/\=]*
中)。
这意味着正则表达式引擎必须尝试在违规字符之前的字符串"FREIGABE
的所有可能排列,然后才能决定不匹配。
这是一个非常高的数字,可能会让引擎忙碌几个小时。将反斜杠添加到字符类后,正则表达式可以匹配。
预防:使用占有量词(*+
和++
)以避免无用的回溯:
public static Pattern FTRECT_PATTERN = Pattern.compile( "\\s*([\\w]+)?\\:?\\s*ftrect\\s+((\\d*\\.?\\d*\\s?)++)\\s*\"?([\\w\\s\\.\\%\\/\\=]*+)?\"?\\s*" );
更好的清理解决方案是:
public static Pattern FTRECT_PATTERN = Pattern.compile("\\s*(\\w*):?\\s*ftrect\\s+((\\b\\d*(?:\\.\\d+)?\\b\\s?)+)\\s*\"?([\\\\\\w\\s.%/=]*+)?\"?\\s*");