2012-03-11 63 views
7

我一直很開心地運行Regex replaceAllIn很長一段時間,但當replacement字符串看起來像一個正則表達式時遇到了問題。以下說明了這個問題(Scala 2.9.1-1)。需要注意的是,真正的問題是空間要複雜得多,因此使用一個簡單的解決方案的思路是不是真正站得住腳的(只是爲了搶佔不可避免「你爲什麼不試試...」:d)scala正則表達式replaceAllIn不能替換時,替換字符串看起來像一個正則表達式?

val data = "val re = \"\"\"^[^/]*://[^/]*/[^/]*$\"\"\".r" 
val source = """here 
LATEX_THING{abc} 
there""" 
val re = "LATEX_THING\\{abc\\}".r 
println(re.replaceAllIn(source, data)) 

這呈現了以下錯誤:

java.lang.IllegalArgumentException: Illegal group reference 

如果我改變data從什麼是喜歡簡單的東西:

val data = "This will work" 

然後一切都很好。

它看起來像replaceAllIn以某種方式查找第二個字符串,並將其用作另一個RE來引用從第一個RE中記住的內容......但文檔對此沒有提及。

我錯過了什麼?

編輯:好了,所以看java.util.regex.Matcher下課後,它似乎是預期的解決方法是:

re.replaceAllIn(source, java.util.regex.Matcher.quoteReplacement(data)) 

回答

9

你需要逃避你替換字符串$

val data = "val re = \"\"\"^[^/]*://[^/]*/[^/]*\\$\"\"\".r" 

否則它被解釋爲組參考的開始(只有在$後跟一個或多個數字時纔有效)。更多細節請參見the documentationjava.util.regex.Matcher

The replacement string may contain references to subsequences captured during the previous match: Each occurrence of $g will be replaced by the result of evaluating group(g) ... A dollar sign ($) may be included as a literal in the replacement string by preceding it with a backslash (\$).

更新,以解決您的評論和編輯上面:是的,你可以使用Matcher.quoteReplacement如果你不字符串文字工作(或者,如果你是,我猜,但逃脫在這種情況下$似乎更容易),並且至少有a chancequoteReplacement將在未來作爲scala.util.matching.Regex上的方法可用。

+1

謝謝先生。我沒有想過要去看Java文檔......我想這就是我從未成爲真正的Java編碼人員的原因。有問題的數據實際上來自Scala源文件。我猜測經驗法則是,除非你確切地知道你得到了什麼,否則先用'$'代替'\ $'來預處理它,然後按照你想要的方式處理它。 – 2012-03-11 21:43:38