replacement
part in replaceFirst(regex,replacement)
can contain references to groups matched by regex
. To do this it is using
$x
syntax where x
is integer representing group number,
${name}
where name
is name of named group (?<name>...)
Because of this ability $
is treated as special character in replacement
, so if you want to make $
literal you need to
- escape it with
\
like replaceFirst(regex,"\\$whatever")
- or let
Matcher
escape it for you using Matcher.quote
method replaceFirst(regex,Matcher.quote("$whatever"))
BUT you shouldn't be using
value = value.replaceFirst("\\{[sdf]\\}", "%" + i + "\\$s");
inside loop because each time you do, you need to traverse entire string to find part you want to replace, so each time you need to start from beginning which is very inefficient.
Regex engine have solution for this inefficiency in form of matcher.appendReplacement(StringBuffer, replacement)
and matcher.appendTail(StringBuffer)
.
appendReplacement
method is adding to StringBuffer all data until current match, and lets you specify what should be put in place of matched by regex part
appendTail
adds part which exists after last matched part
So your code should look more like
StringBuffer sb = new StringBuffer();
int i = 0;
Matcher tagsMatcher = Pattern.compile("\\{[sdf]\\}").matcher(value);
while (tagsMatcher.find()) {
tagsMatcher.appendReplacement(sb, Matcher.quoteReplacement("%" + (i++) + "$s"));
}
value = sb.toString();