Balazs Kelemen
Balazs Kelemen

Reputation: 91

"Safe way" to use java matcher.replaceAll() / appendReplacement()

Most of the cases we replace string segments using regular expression, when the replacement text is a variable, so basically it is not known by the programmer.

However we always forget, that the behavior of java matcher.replaceAll() will very much dependent on the replacement itself. Thus the replacement should not contain any '$' or '\' characters, to provide a naive result.

E.g. the following code throw "java.lang.IndexOutOfBoundsException: No group 2" in case the variable salary equals "$2".

String salary = "$2";
Pattern p = Pattern.compile("SAL");
Matcher m = p.matcher("Salary: SAL");
String s = m.replaceAll(salary);
System.out.println(s);

I know, that if '$' sign is escaped with '\', then we will get the expected result. But then again, the '\' should be escaped with '\' as well. So the proper solution would be:

String salary = "$2";
Pattern p = Pattern.compile("SAL");
Matcher m = p.matcher("Salary: SAL");
String s = m.replaceAll(salary.replace("\\", "\\\\").replace("$", "\\$"));
System.out.println(s);

Now first of all this is not so convenient to use, but also not great performance-wise. (And the same stands for the appendReplacement() method.)

So can you please recommend some more generic solution for the problem?

Upvotes: 1

Views: 363

Answers (1)

Amongalen
Amongalen

Reputation: 3131

In case if you only want to replace a specific substring with the specified literal replacement sequence, you can simply use String.replace(). Something like so:

  String source = "Salary: SAL";
  String target = "SAL";
  String salary = "$2";
  String result = source.replace(target, salary);
  System.out.println(result); // prints "Salary: $2"

It is worth noting, that it only replaces literal substring sequences and won't work if target is a regex.

Upvotes: 0

Related Questions