2012-03-11 151 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