Reputation: 606
Consider the following string:
He ordered a pizza with anchovies. Unfortunately, it wasn't the thing he wanted. Besides, pizza with mushroom, pepperoni and anchovies is much better than the normal pizza with anchovies.
Let's say that you need to change pizza with (ingredients)
to pizza with (ingredients) on a thin crust
.
To do that, I had set a Regex:
(?i:pizza with [a-zA-Z,\s]*?anchovies)
This captures three matches. Then, I proceed to add the on a thin crust
to each match using the following code:
Pattern p = Pattern.compile("(?i:pizza with [a-zA-Z,\s]*?anchovies)");
Matcher m = p.matcher(string);
while(m.find())
{
string = string.replace(m.group(), m.group() + "on a thin crust.");
}
The output of this will then be:
He ordered a pizza with anchovies on a thin crust on a thin crust. Unfortunately, it wasn't the thing he wanted. Besides, pizza with mushroom, pepperoni and anchovies is much better than the normal pizza with anchovies on a thin crust on a thin crust.
What happened:
The first match pizza with anchovies
is the same as the last match. Hence, using String.replace
caused the first and last match to change to pizza with anchovies on a thin crust
. Since, we are looping through all matches, the last match will still occur and the replace function will also replace the first match (since first match and last match are the same). Hence, we get double on a thin crust
.
Q:
Is there a way to replace a Regex match at the current match only?
Upvotes: 7
Views: 1608
Reputation: 626738
Do it with a single replaceAll
using $0
backreference to the whole match:
String s = "He ordered a pizza with anchovies. Unfortunately, it wasn't the thing he wanted. Besides, pizza with mushroom, pepperoni and anchovies is much better than the normal pizza with anchovies.";
s = s.replaceAll("(?i)pizza with [a-zA-Z,\\s]*?anchovies", "$0 on a thin crust");
System.out.println(s);
// => He ordered a pizza with anchovies on a thin crust. Unfortunately, it wasn't the thing
// he wanted. Besides, pizza with mushroom, pepperoni and anchovies on a thin crust is
// much better than the normal pizza with anchovies on a thin crust.
See the Java demo
This way, you will avoid replacing already replaced texts since replaceAll()
process all, multiple, non-overlapping occurrences of the substrings meeting your regex pattern.
Upvotes: 7