2013-01-24 22 views
7

可能重複:
String.replaceAll() anomaly with greedy quantifiers in regex的Java的replaceAll與反向引用

我正在寫一個使用Matcher#replaceAll代碼,發現下面的結果非常令人困惑:

Pattern.compile("(.*)").matcher("sample").replaceAll("$1abc"); 

現在,我期望輸出爲sampleabc,但Java拋出我sampleabcabc

有沒有人有任何想法爲什麼?

現在,當然,當我錨定模式(^(.*)$)問題消失。但我不知道爲什麼地獄replaceAll做這樣的雙重替換。

而要雪上加霜,下面的代碼:

Pattern.compile("(.*)").matcher("sample").replaceFirst("$1abc") 

按預期工作,只返回sampleabc

+0

@Pshemo:你說得對。對不起,我沒有找到這個事先提交。 – Wejn

回答

5

由於某種原因,它看上去與輸入末尾的空字符串匹配。 (我可以看到爲什麼它會匹配;我很好奇它匹配一次且僅一次)。

如果更改replaceAll("$1abc")replaceAll("'$1'abc")結果是'sample'abc''abc

請注意,如果您將(.*)更改爲(.+)那麼它可以正常工作,因爲它必須至少匹配一個字符。

Matcher matcher = Pattern.compile("(.*)").matcher("sample"); 

while (matcher.find()) { 
    System.out.printf("%d to %d\r\n", 
         matcher.start(), 
         matcher.end()); 
} 

...它輸出:

0 to 6 
6 to 6 
+0

+1先回答_and_解決方案... – yair

+0

我找不到記錄在哪裏,您可以參考「替換爲」字符串中帶有$ 1,$ 2等的捕獲組結果。在模式中,javadoc被稱爲你引用'\ 1','\ 2'等。 – George

+0

@George:這是因爲你正在尋找'Pattern' javadoc而不是['Matcher.replaceAll'](http:/ /docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#replaceAll-java.lang.String-),其中聲明:「美元符號可被視爲對所捕獲子序列的引用,如所述上面,反斜槓用於轉義替換字符串中的文字字符。「對於「如上所述」部分,請參閱文檔「appendReplacement」。 –

5

有兩件事情怎麼回事解釋爲什麼出現這種情況:

診斷是通過該代碼證實

  • (.*)將成功匹配空字符串。
  • 比賽成功後,另一場比賽將在上一場比賽結束後的一個位置進行嘗試。

因此,在整個字符串"sample"匹配後,嘗試在e之後的另一個匹配。即使沒有留下字符,比賽成功並且發生第二次替換。

因爲正則表達式引擎總是前進,所以不會出現其他替換。在最後一個字符是一個有效的起始索引之後,所以空字符串會匹配一次,但是在匹配空字符串之後,沒有更多有效的起始位置供正則表達式引擎嘗試匹配。

作爲將字符串錨點的開頭添加到您的正則表達式的替代方法,您可以通過將(.*)更改爲(.+)來修改您的正則表達式,使其匹配一個或多個字符。