Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matcher's appendReplacement method ignores the replacement's backslashes

Tags:

java

regex

I have a string s and a regex. I would like to replace each match of the regex in s with a replacement string. The replacement string might contain one or more backslashes. To perform the replacement, I'm using Matcher's appendReplacement method.

The problem with appendReplacement is that it ignores all the backlashes it encounters in the replacement string. So if I try replacing the substring "match" in the string "one match" with the replacement string "a\\b", then appendReplacement results in "one ab" instead of "one a\\b"*:

Matcher matcher = Pattern.compile("match").matcher("one match");
StringBuffer sb = new StringBuffer();
matcher.find();
matcher.appendReplacement(sb, "a\\b");
System.out.println(sb); // one ab

I have taken a look at appendReplacement's code, and found out that it skips any encountered backslash:

if (nextChar == '\\') {
    cursor++
    nextChar = replacement.charAt(cursor);
    ...
}

How can I replace each match with a replacement string that contains backslashes?

(*) - Note that there's a single backslash in "a\\b", not two. The backslash is just escaped.

like image 579
snakile Avatar asked Dec 09 '14 12:12

snakile


3 Answers

You need to double escape the backslash i.e.:

matcher.appendReplacement(sb, "a\\\\b");

Full Code:

Matcher matcher = Pattern.compile("match").matcher("one match");
sb = new StringBuffer();
matcher.find();
matcher.appendReplacement(sb, "a\\\\b");
System.out.println(sb); //-> one a/b

Reason being that Java allows you to use backreferences like $1, $2 etc in replacement string and that enforces same escaping mechanism for backslash as in the main regex.

like image 195
anubhava Avatar answered Nov 03 '22 12:11

anubhava


You need to escape escapes

Matcher matcher = Pattern.compile("match").matcher("one match");
StringBuffer sb = new StringBuffer();
matcher.find();
matcher.appendReplacement(sb, "a\\\\b");
System.out.println(sb);

Alternatively use replace()

String test="one match";
test=test.replace("match", "a\\b");
System.out.println(test);

output :

one a\b
like image 37
Darshan Lila Avatar answered Nov 03 '22 12:11

Darshan Lila


Use Matcher.quoteReplacement if the replacement string should be treated literally. It escapes all \ characters and also $ characters.

String replacement= "a\\b" 
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));    
like image 1
kapex Avatar answered Nov 03 '22 10:11

kapex