JDK-5024613 : StringIndexOutOfBoundException in String.replaceAll()
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.regex
  • Affected Version: 1.4.2,5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2004-03-31
  • Updated: 2005-10-21
  • Resolved: 2005-10-21
Related Reports
Duplicate :  
Duplicate :  
Description
Name: rmT116609			Date: 03/31/2004


FULL PRODUCT VERSION :
java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)

java version "1.5.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta-b32c)
Java HotSpot(TM) Client VM (build 1.5.0-beta-b32c, mixed mode)

FULL OS VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Exception thrown when invoking replaceAll("\\\\", "\\\\\\") on a String.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run the testcase below. This will throw the exception.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The documentation is quite vague on the role of backslashes in the replacement string. The sentences:

  "Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string. Dollar signs may be treated as references to captured subsequences as described above, and backslashes are used to escape literal characters in the replacement string."

Are confusing. "may cause the result to be different"? depending on what?

I was trying to replace single occurences of backslashes with double occurrences. At first I thought it should be
  replaceAll("\\\\", "\\\\")

as the first one is documented as a regexp and the second as a string. This appears to do nothing. Then I tried adding two backslashes to the replacement String, just for fun, and I got the exception. 

ACTUAL -
an exception

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String ind
ex out of range: 3
        at java.lang.String.charAt(String.java:444)
        at java.util.regex.Matcher.appendReplacement(Matcher.java:551)
        at java.util.regex.Matcher.replaceAll(Matcher.java:661)
        at java.lang.String.replaceAll(String.java:1663)
        at test.main(test.java:7)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.regex.*;

public class test {
  static String txt = ".\\try\\this";

  public static void main(String args[]) {
    System.out.println(txt.replaceAll("\\\\", "\\\\\\"));
  }
}

---------- END SOURCE ----------
(Incident Review ID: 218772) 
======================================================================

Name: rmT116609			Date: 03/31/2004


A DESCRIPTION OF THE PROBLEM :
replaceAll("\\$", "\\\\$") will raise an exception which is not correct.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
look at this class:
class TestReplace {
	public static void main(String[] args) {
		String x = "$$$$$";
		String x1 = x.replaceAll("\\$", "\\\\$");
		System.out.println(x1);
	}
}
i think the correct output will be "\$\$\$\$\$"

EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual -
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 3
        at java.lang.String.charAt(String.java:444)
        at java.util.regex.Matcher.appendReplacement(Matcher.java:559)
        at java.util.regex.Matcher.replaceAll(Matcher.java:661)
        at java.lang.String.replaceAll(String.java:1663)
        at TestReplace.main(TestReplace.java:4)

Expected -
failed to replace.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 3
        at java.lang.String.charAt(String.java:444)
        at java.util.regex.Matcher.appendReplacement(Matcher.java:559)
        at java.util.regex.Matcher.replaceAll(Matcher.java:661)
        at java.lang.String.replaceAll(String.java:1663)
        at TestReplace.main(TestReplace.java:4)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
class TestReplace {
	public static void main(String[] args) {
		String x = "$$$$$";
		String x1 = x.replaceAll("\\$", "\\\\$");
		System.out.println(x1);
	}
}
---------- END SOURCE ----------
(Review ID: 245724)
======================================================================
###@###.### 11/1/04 23:18 GMT

Comments
EVALUATION As a workaround, String.replace() should be used if a "literal" replacement operation is desired. We've added more "developer friendly" api doc for replaceFirst() and replaceAll() to address this issue, under bug#6280695. Close this one as a dup.
21-10-2005

WORK AROUND We have now provided Matcher.quoteReplacement for literal replacement strings, Pattern.quote for literal pattern Strings as well as the LITERAL flag for literal patterns. Using these should help although you will still have to deal with javac's escape processing. ###@###.### 2004-03-31
31-03-2004

EVALUATION The StringIndexOutOfBounds exception should be translated to something more helpful to the user. It is unfortunate that the mechanics of double escape processing are so confusing. We added mention of this backslash issue in an attempt to highlight that there is another escape process going on on top of that done by javac. ###@###.### 2004-03-31
31-03-2004