Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I need a clarification about "character to be escaped is missing" exception

Tags:

java

string

I have the following code:

public class Test {

public static void main(String[] args) {
    String path = "${file.path}/fld/";
    String realValue = "C:\\path\\smtg\\";
    String variable = "${file.path}";
    path = path.replaceAll("\\$\\{" + variable.substring(2, variable.length() - 1) + "\\}", realValue);
    System.out.println(path);
    }
}

which gives me the following exception:

Exception in thread "main" java.lang.IllegalArgumentException: character to be escaped is missing
at java.util.regex.Matcher.appendReplacement(Matcher.java:809)
at java.util.regex.Matcher.replaceAll(Matcher.java:955)
at java.lang.String.replaceAll(String.java:2223)
at testCode.Test.main(Test.java:9)

I already find some question about this problem, but still I don't understand this error. Can someone explain me what's going on?

I know that replace would work well, but unfortunately my collegues do not want to modify this code. So I need to know the exact problem to deliver a solution, because in other installations it works.

like image 459
Lorelorelore Avatar asked Aug 06 '18 08:08

Lorelorelore


2 Answers

For your particular case you need to do the following:

public static void main(String[] args) {
    String path = "${file.path}/fld/";
    String realValue = "C:\\\\path\\\\smtg\\\\";  //Notice the double slashes here
    String variable = "${file.path}";
    path = path.replaceAll("\\$\\{" + variable.substring(2, variable.length() - 1) + "\\}", realValue);
    System.out.println(path);
}

And now for the explanation. When you do a replaceAll the second part of a string is also interpreted by Java and has special characters like \ and $. So in order to add a \ in the string you need to escape it and it becomes \\ and if you want to use it in the resulting string literal you need to escape each one of them so it becomes "\\\\"

If you check java doc on the replaceAll method in a matcher: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html#replaceAll%28java.lang.String%29

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.

A simpler solution in your case would be to use replace instead of replaceAll since your pattern is pretty straightforward and you don't need a regex support, you can just match against a full string "${file.path}"

path = path.replace("${file.path}", realValue);
//or even
path = path.replace(variable, realValue);
like image 173
Veselin Davidov Avatar answered Oct 21 '22 12:10

Veselin Davidov


ReplaceAll is treating it's input as a regular expression. There are some valid escape expressions in regex, like \w for a word character or \s for any whitespace. If file.path is a Windows path containing \ it may well have invalid escape sequences. Any any case it will not have the meaning you intend it to have.

The other occurrences that worked were they on a unix like environment? (unix, linux, os-x etc) if so it could of worked because those environments use / for path separators.

Before calling replaceAll you could try

variable = variable.replace("\\", "\\\\"); // to escape any \ in path.
like image 25
David Waters Avatar answered Oct 21 '22 14:10

David Waters