Fun with Regular Expressions: ANT-style Variable Replacing in Strings
I recently felt the need to write a piece of code that resolves ANT-style variables in a string. Suppose you have a property file similar to this one:
propertyA=SomeValue
propertyB=${propertyA}.SomeOtherValue
listofThings=${propertyA}, ${propertyB}, constantValue
Let's further assume you want to read property listofThings, and resolve the variables. Isn't that a perfect job for regular expressions?
Using Regex Tester, I came up with the following regular expression to find occurrence of ${variable}:
\$\{(.+?)\}
Using java.util.regex.Pattern and java.util.regex.Matcher to find all occurrences is rather trivial:
Pattern re = Pattern.compile("\\$\\{(.+?)\\}");
Matcher m = re.matcher(sourcestring);
while (m.find()) {
String variable = m.group(1);
System.out.println(variable);
}
Replacing the variables with their concrete values is not so trivial. You might be tempted to use String.substring():
value = sourcestring.substring(0, m.start()) + replacement + (sourcestring.substring(m.end()));
But this will modify the source string, basically throwing the matcher out of the curve.
Looking at the matcher API, I found java.util.regex.Matcher.appendReplacement(StringBuffer, String) and java.util.regex.Matcher.appendTail(StringBuffer). These two little gems to the trick:
private String resolve(String sourcestring, Properties props) {
Pattern re = Pattern.compile("\\$\\{(.+?)\\}");
Matcher m = re.matcher(sourcestring);
StringBuffer result = new StringBuffer();
while (m.find()) {
String variable = m.group(1);
String resolved = resolve(props.getProperty(variable), props);
m.appendReplacement(result, resolved);
}
m.appendTail(result);
return result.toString();
}
Regular Expressions do save the day!
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)







Comments
Eran Harel replied on Fri, 2009/09/11 - 8:41am
Danny Lee replied on Fri, 2009/09/11 - 9:00am
I use similar approach for complex case.
In simple cases I use
Dave Moten replied on Sun, 2009/09/13 - 9:09pm
very nice, I like it and I'm using it. I've modified it a bit though so that name=${reference} will come through as name=${reference} untouched if reference is not set. At the moment your code generates a NullPointerException which may be good for some but not for me. My modification is:
private String resolve(String sourcestring, Properties props) {
if (sourcestring==null) return null;
Pattern re = Pattern.compile("\\$\\{(.+?)\\}");
Matcher m = re.matcher(sourcestring);
StringBuffer result = new StringBuffer();
while (m.find()) {
String variable = m.group(1);
String resolved = resolve(props.getProperty(variable), props);
if (resolved!=null) m.appendReplacement(result, resolved);
}
m.appendTail(result);
return result.toString();
}
Thanks a lot