Peter Friese is a software engineer with 15+ years hands-on experience in software development, technical writing and public speaking. Peter works as a software engineering consultant at Zühlke Engineering. Having worked on a host of industry projects in diverse domains and being an active committer on a number of open source projects, he has in-depth knowledge in a broad range of technologies. His main areas of expertise are model-driven software development, cross-platform mobile development (iPhone, Android, Windows Phone 7, and mobile web) and Eclipse tooling. Peter blogs at http://www.peterfriese.de and tweets at @peterfriese. Peter is a DZone MVB and is not an employee of DZone and has posted 29 posts at DZone. View Full User Profile

Fun with Regular Expressions: ANT-style Variable Replacing in Strings

09.11.2009
| 8689 views |
  • submit to reddit

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!

From http://www.peterfriese.de

Published at DZone with permission of Peter Friese, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Eran Harel replied on Fri, 2009/09/11 - 8:41am

Why not use a ResourceBundle / MessageFormat / ChoiceFormat?

Danny Lee replied on Fri, 2009/09/11 - 9:00am

I use similar approach for complex case.

In simple cases I use

org.apache.commons.lang.text.StrSubstitutor
because it's a little bit faster.  

 

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

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.