Kohei Nozaki's blog 

Complex string replacing on Java


Posted on Tuesday Feb 10, 2015 at 10:06PM in Technology


Sometimes annoying requirement of string replacing will risen. everytime I forgotten how to do it so I leave this as my note. also there’s a JUnit test case.

Requirement

Assume we have following string literals. we have to convert input string to expected.

String input = "<li><a href=\"../../jbatch/hello/\" >anchor</a></li>";
String expected = "<li><a href=\"/entry/articles-jbatch-hello\" >anchor</a></li>";

Solutions

Using numbered groups

Pattern p = Pattern.compile("(<a href=\")\\.\\./\\.\\./(.*)/(.*)/\"");
Matcher matcher = p.matcher(input);
String result = matcher.replaceAll("$1/entry/articles-$2-$3\"");

Using named groups

Pattern p = Pattern.compile("(?<prefix><a href=\")\\.\\./\\.\\./(?<category>.*)/(?<handle>.*)/\"");
Matcher matcher = p.matcher(input);
String result = matcher.replaceAll("${prefix}/entry/articles-${category}-${handle}\"");

Using Matcher#appendReplacement(). this one is most flexible.

Pattern p = Pattern.compile("(?<prefix><a href=\")(?<url>.*)\"");
Matcher matcher = p.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
	// any complex logic can be placed here
	String url = matcher.group("url");
	String[] urls = url.split("/");
	matcher.appendReplacement(sb, "${prefix}/entry/articles-" + urls[2] + "-" + urls[3] + "\"");
}
matcher.appendTail(sb);
String result = sb.toString();

Escaping special character for replacement

$ have special meaning for replacement string, but sometimes we may need to use $ as just a literal. for such case, we can use Matcher.quoteReplacement() for escaping $ character as follows:

String input = "../../jbatch/hello/";
String expected = "../../$1/${name}/";
Pattern p = Pattern.compile("(?<prefix>\\.\\./\\.\\.)/.*/.*/");
String result = p.matcher(input).replaceAll("${prefix}/" + Matcher.quoteReplacement("$1/${name}") + "/");