2011-05-12 114 views
12

我有一个Java正则表达式模式和一个我想完全匹配的句子,但是对于一些句子它错误地失败了。为什么是这样? (为简单起见,我不会用我的正则表达式复杂,但只是 “*”)Java正则表达式总是失败

System.out.println(Pattern.matches(".*", "asdf")); 
System.out.println(Pattern.matches(".*", "[11:04:34] <@Aimbotter> 1 more thing")); 
System.out.println(Pattern.matches(".*", "[11:04:35] <@Aimbotter> Dialogue: 0,0:00:00.00,0:00:00.00,Default,{Orginal LV,0000,0000,0000,,[???]??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????} ")); 
System.out.println(Pattern.matches(".*", "[11:04:35] <@Aimbotter> Dialogue: 0,0:00:00.00,0:00:00.00,Default,{Orginal LV,0000,0000,0000,,[???]????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????} ")); 

输出:

true 
true 
true 
false 

注意的是,第四句包含10个的Unicode控制字符\ u0085之间问号,通常字体不显示。第三个和第四个句子实际上包含相同数量的字符!

+0

这是特别奇怪,因为Java是一个Unicode正则表达式引擎... – 2011-05-12 12:52:10

+0

这将是糟糕的,如果Java的不知道Unicode行终止(http://www.fileformat.info/info/unicode/char /85/index.htm) – rurouni 2011-05-12 13:03:18

+0

... @ tchrist不久将告诉我们关于java正则表达式引擎是如何破坏的。 – aioobe 2011-05-12 13:05:17

回答

13

使用

Pattern.compile(".*",Pattern.DOTALL) 
如果你想

。以匹配控制字符。默认情况下,它只匹配可打印的字符。

从JavaDoc的:

“以DOTALL模式下,表达式匹配任何字符,包括一个线路终端默认该表达式不匹配行终止

DOTALL模式也可以通过使能。嵌入标志表达式(s是“单行”模式,这是什么,这是所谓的Perl中的一个记忆。)”

代码的模式(有你\ u0085)(S):。

/** 
* Implements the Unicode category ALL and the dot metacharacter when 
* in dotall mode. 
*/ 
static final class All extends CharProperty { 
boolean isSatisfiedBy(int ch) { 
    return true; 
} 
} 

/** 
* Node class for the dot metacharacter when dotall is not enabled. 
*/ 
static final class Dot extends CharProperty { 
boolean isSatisfiedBy(int ch) { 
    return (ch != '\n' && ch != '\r' 
       && (ch|1) != '\u2029' 
       && ch != '\u0085'); 
    } 
} 
+0

谢谢,(?s)工作。我没有尝试Pattern.DOTALL,因为我有很多不同的编译模式,而且我只需要使用(?s)一次(在大多数模式中包含的字符串常量中)。 – 2011-05-12 17:12:27

4

答案是这样的问题:10的Unicode控制符\ u0085

的Unicode控制符的arent承认*就像\ n

1

我相信问题是\ u0085代表一个换行符。如果你想多行匹配,你需要使用Pattern.MULTILINEPattern.DOTALL。这不是它是Unicode的事实 - '\ n'也会失败。

要使用它:Pattern.compile(regex, Pattern.DOTALL).matcher(input).matches()

2

Unicode/u0085是换行符,因此您必须将(?s)(点全部匹配)添加到您的正则表达式的开头,或者在编译正则表达式时添加标志。

Pattern.matches("(?s).*", "blahDeBlah\u0085Blah") 
+1

不是'(?m)' - 多行模式意味着'^'和'$'匹配行的开始/结尾。你想'(?s)'为单线模式。是的,这是令人困惑的(这个想法是“将整个输入视为一条线”)。 – 2011-05-12 13:34:58

+0

哎呦,你是正确的先生。固定。 – 2011-05-12 13:46:34