2012-01-17 36 views
14

我剛剛觀察到這種行爲;正則表達式在多行模式下不匹配空字符串(Java)

Pattern p1 = Pattern.compile("^$"); 
Matcher m1 = p1.matcher(""); 
System.out.println(m1.matches()); /* true */ 

Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE); 
Matcher m2 = p2.matcher(""); 
System.out.println(m2.matches()); /* false */ 

這讓我覺得奇怪,最後一個陳述是錯誤的。這是文檔所說的;

默認情況下,正則表達式^和$忽略行結束符,並且只能匹配整個輸入序列的開始和結束。如果激活MULTILINE模式,則^在輸入開始處和任何行終止符之後匹配,除了輸入結束處。在MULTILINE模式下$匹配行終止符之前或輸入序列的結尾。 http://docs.oracle.com/javase/1.4.2...

從我得到這個,它應該匹配?以下情況更令人困惑;

Pattern p3 = Pattern.compile("^test$"); 
Matcher m3 = p3.matcher("test"); 
System.out.println(m3.matches()); /* true */ 

Pattern p4 = Pattern.compile("^test$", Pattern.MULTILINE); 
Matcher m4 = p4.matcher("test"); 
System.out.println(m4.matches()); /* true */ 

那麼這是什麼?我如何理解這一點?我希望有人能夠闡明這一點,會非常感激。

+1

這是Java SE 6中(MacOS X系統默認) – 2012-01-17 14:28:22

+0

剛在OpenJDK的(IcedTea6 1.9.10)和相同的奇怪的行爲成立。 – 2012-01-17 14:33:41

+0

同樣在Oracle JRE 7 – Ingo 2012-01-18 11:25:42

回答

6

如果MULTILINE模式被激活則^在 輸入開始和狀態之外的任何行結束後一致在輸入結束時。

由於您在輸入的末尾,^無法在多行模式下匹配。

這是令人驚訝的,甚至令人厭惡,但根據其文件。

+0

這個「輸入結束時除外」僅指「和任何行結束符後」。由於我們沒有行終止符,因此我們處於輸入的開頭,所以它應該匹配。 – stema 2012-01-17 15:13:12

+0

'/^$/m','/^$ /','/ \ A \ Z/m','/ \ A \ Z /','\ A \ z /','/ ^/m', '/ $/m'匹配Perl中的空字符串。這是平臺問題嗎?所有文檔都說同樣的事情。奇怪! – sln 2012-01-17 15:40:59

+0

@stema你怎麼知道這件事?我的意思是,行爲看起來像是否參考^是否可以匹配。 – Ingo 2012-01-17 18:51:51

2

讓我們更關注一些在你的第二個例子:

Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE); 
Matcher m2 = p2.matcher(""); 
System.out.println(m2.matches()); /* false */ 

所以,你必須在平方米的線,即空或包含底線的唯一字符,並沒有其他字符。因此,你的模式,以符合給定的線,應該只有「$」,即:

// Your example 
Pattern p2 = Pattern.compile("^$", Pattern.MULTILINE); 
Matcher m2 = p2.matcher(""); 
System.out.println(m2.matches()); /* false */ 

// Let's check if it is start of the line 
p2 = Pattern.compile("^", Pattern.MULTILINE); 
m2 = p2.matcher(""); 
System.out.println(m2.matches()); /* false */ 

// Let's check if it is end of the line 
p2 = Pattern.compile("$", Pattern.MULTILINE); 
m2 = p2.matcher(""); 
System.out.println(m2.matches()); /* true */ 
+0

它沒有解決OP的問題:''^ $「'沒有'MULTILINE'模式匹配,但在'MULTILINE'模式下沒有這樣做。 – anubhava 2012-01-17 14:57:27

+0

@anubhava它是,因爲我們沒有序列的開始,但只有結束。 根據JDK API: 在多行模式下,表達式^和$恰好分別匹配行終止符或輸入序列的末尾。默認情況下,這些表達式只匹配整個輸入序列的開始和結束。 (http://docs.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html) 單行,我們得到一個空字符串,並在多行模式 - 空序列。 – wanderlust 2012-01-17 15:05:57

+0

+1。我感覺合理。 – 2012-01-17 15:17:52

1

聽起來像一個錯誤。在多線模式下,「^」和「$」可以被解釋爲在內部線邊界處匹配。 Java可能沒有擴展變量狀態結構,就像Perl一樣。我不知道這是否是一個原因。

事實上,/^test$/m比賽只是證明在多行模式^ $工作除了當字符串(在Java中)空的,但顯然是空字符串多行模式測試是可笑的,因爲對於/^$/工作。

測試在Perl,一切正常:

if ("" =~ /^$/m ) { print "/^\$/m matches\n"; } 
if ("" =~ /^$/ ) { print "/^\$/  matches\n"; } 
if ("" =~ /\A\Z/m) { print "/\\A\\Z/m matches\n"; } 
if ("" =~ /\A\Z/ ) { print "/\\A\\Z/ matches\n"; } 
if ("" =~ /\A\z/ ) { print "/\\A\\z/ matches\n"; } 
if ("" =~ /^/m ) { print "/^/m  matches\n"; } 
if ("" =~ /$/m ) { print "/\$/m  matches\n"; } 


__END__ 


/^$/m matches 
/^$/  matches 
/\A\Z/m matches 
/\A\Z/ matches 
/\A\z/ matches 
/^/m  matches 
/$/m  matches 
+0

同意,我測試'/^$/m'和'/^$ /'爲.net,它也按預期工作。 – stema 2012-01-17 15:33:14