Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IllegalArgumentException: Illegal group reference while replaceFirst

Tags:

java

regex

I'm trying to replace first occurence of String matching my regex, while iterating those occurences like this:

(this code is very simplified, so don't try to find some bigger sense of it)

Matcher tagsMatcher = Pattern.compile("\\{[sdf]\\}").matcher(value);

int i = 0;
while (tagsMatcher.find()) {
    value = value.replaceFirst("\\{[sdf]\\}", "%" + i + "$s");
    i++;
}

I'm getting IllegalArgumentException: Illegal group reference while executing replaceFirst. Why?

like image 355
Jacek Kwiecień Avatar asked Dec 25 '22 18:12

Jacek Kwiecień


2 Answers

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();
like image 110
Pshemo Avatar answered May 01 '23 08:05

Pshemo


You need to escape the dollar symbol.

value = value.replaceFirst("\\{[sdf]\\}", "%" + i + "\\$s");

Illegal group reference error occurs mainly because of trying to refer a group which really won't exists.

like image 37
Avinash Raj Avatar answered May 01 '23 10:05

Avinash Raj