2012-02-10 54 views
4

有一個關於正則表達式的問題,並試圖回答我發現了另一個奇怪的事情。在正則表達式中的奇怪行爲

String x = "X"; 
System.out.println(x.replaceAll("X*", "Y")); 

這打印YY。爲什麼??

String x = "X"; 
System.out.println(x.replaceAll("X*?", "Y")); 

而這種打印YXY

爲什麼不願意正則表達式不匹配 'X' 字?有"noting"X"nothing",但爲什麼先不匹配三個符號,匹配兩個,然後一個而不是三個?和第二次正則表達式匹配只有"nothing" s而不是X

+0

在Perl/PCRE中用'X *?'代替將導致'YYY'。 – Qtax 2012-02-10 13:54:56

回答

8

讓我們看看它們依次是:

"X".replaceAll("X*", "Y") 

有兩場比賽:

  1. 在字符位置0,X匹配,並且被替換爲Y
  2. 在字符位置1處,匹配空字符串,並將Y添加到輸出中。

最終結果:YY

"X".replaceAll("X*?", "Y") 

還有兩個匹配:

  1. 在字符位置0,空字符串匹配時,並Y被添加到輸出。 此位置上的字符X未被匹配消耗,因此會逐字複製到輸出中。
  2. 在字符位置1處,匹配空字符串,並將Y添加到輸出中。

最終結果:YXY

+0

在第一種情況下,在第二步中(2.在字符位置1 ...)但沒有位置1,它超出了字符串的邊界,不是嗎?在第一步之後,一切都應該結束,因爲字符串結束 – shift66 2012-02-10 13:38:43

+0

@Ademiban:不完全。有一個位置'1'。考慮下面的正則表達式:'「$」'。根據定義,它可以匹配的* only *位置在字符串的最後一個字符之後。在這個例子中,這將位於'1'位置。正則表達式可以產生零長度匹配。 – NPE 2012-02-10 13:39:56

+0

很好的回答!讓我添加一個可能有趣的筆記;)在第二種情況下,X自從*以來不匹配?意味着懶惰的匹配,即*之前的元素?如果仍然產生有效結果,則最好不匹配。 – 2012-02-10 13:44:50

1

*是一個棘手的'量詞',因爲它意味着'0或更多'。因此,它也匹配'0次X'(即空字符串)。

我會用

"X".replaceAll("X+", "Y") 

其中有預期的行爲。

0

在您的第一個示例中,您使用的是「貪婪」量詞。這意味着在嘗試第一次匹配之前,輸入字符串被強制完全讀取,所以第一次嘗試的是整個輸入。如果輸入匹配,匹配器會越過輸入字符串,並在字符串末尾執行零長度匹配,因此您會看到兩個匹配項。在第一次匹配嘗試成功之前,貪婪的匹配器永遠不會退回到字符X之前的零長度匹配。

在第二個示例中,您使用的是與「貪婪」相反的「不情願」量詞。它從一開始就開始,並嘗試在未來的時間匹配一個字符(如果必須的話)。因此匹配「X」字符之前的零長匹配,匹配器向前移動1(這就是爲什麼您仍然可以在輸出中看到「X」字符),其中下一個匹配現在是「X 」。
這裏有一個很好的教程:http://docs.oracle.com/javase/tutorial/essential/regex/quant.html