8

I've been happily running a Regex replaceAllIn for quite a while but ran into a problem when the replacement string had something that looked like a regex in it. The following illustrates the problem (Scala 2.9.1-1). Note that the real problem space is much more complex, so the idea of using a simpler solution isn't really tenable (just to preempt the inevitable "Why don't you try ..." :D)

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

This presents with the following error:

java.lang.IllegalArgumentException: Illegal group reference

If I change data from what it was to something simple like:

val data = "This will work"

Then everything's fine.

It looks like replaceAllIn is somehow looking in the second string and using it as another RE to reference what was remembered from the first RE... but the docs say nothing about this.

What am I missing?

edit: Ok, so after looking at the java.util.regex.Matcher class, it would seem that the intended fix is:

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

1 Answer 1

10

You need to escape the $ in your replacement string:

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

Otherwise it's interpreted as the beginning of a group reference (which would only be valid if the $ were followed by one or more digits). See the documentation for java.util.regex.Matcher for more detail:

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 (\$).

Update to address your comment and edit above: Yes, you can use Matcher.quoteReplacement if you're not working with string literals (or if you are, I guess, but escaping the $ seems easier in that case), and there's at least a chance that quoteReplacement will be available as a method on scala.util.matching.Regex in the future.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you sir. It didn't occur to me to head to the Java docs... that's what I get for never being a real Java coder, I guess. The data in question actually comes from a Scala source file. I guess the rule of thumb is, unless you know exactly what you've got, preprocess it first by substituting the $ for \$ and then process it the way you want.
As of Scala 2.12.6 quoteReplacement is now available in scala.util.matching.Regex scala-lang.org/api/2.12.6/scala/util/matching/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.