当匹配包含\ n的行时,Java Pattern.matcher()会冻结

我遇到了一个我觉得非常有趣的问题。 我正在使用正则表达式对文本文件进行一些基本的解析,并且在匹配此行时它总是会冻结

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*" ); 

我仍然不知道为什么没有抛出exception。

这是因为灾难性的回溯 。 您的测试字符串包含一个文字反斜杠(在"...\\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*");