Home > Software engineering >  Java Regex: Replace all ${placeholders} with map values
Java Regex: Replace all ${placeholders} with map values

Time:03-20

I'm trying to replace all occurrences of ${placeholders} with values from a lookup map of placeholder -> value

The code below doesn't quite cut it.

Expected :[foobar, foobar, foobar, afoobbarc]
Actual   :[foobar, foobar, ${key1}bar, a${key1}bbarc]

Can anyone think of a better regex?

private static final Pattern replaceRegex = Pattern.compile(".*(\\$\\{?([^}] )}).*");
public static String resolvePlaceholder(Map<String, String> map, String s){
  String returnValue = s;
  for (Matcher m = replaceRegex.matcher(s); m.find(); ) {
    if (map.containsKey(m.group(2))) {
      returnValue = returnValue.replace(m.group(1), map.get(m.group(2)));
    }
  }
  return returnValue;
}

@Test
public void test() {
  // Given a map of a million entries
  Map<String, String> veryBigMap = new HashMap<>();
  veryBigMap.put("key1", "foo");
  veryBigMap.put("key2", "bar");
  // And test cases
  Stream<String> testCases = Stream.of("${key1}bar", "foo${key2}", "${key1}${key2}", "a${key1}b${key2}c");

  // When resolving placeholders
  List<String> actual = testCases
      .map(t -> resolvePlaceholder(veryBigMap, t))
      .collect(Collectors.toList());

  // Then placeholders get replaced
  assertEquals(
      Arrays.asList("foobar", "foobar", "foobar", "afoobbarc"),
      actual);
}

Many thanks

Fil

CodePudding user response:

The following version, which uses a StringBuffer to iteratively build the output string, should work:

private static final Pattern replaceRegex = Pattern.compile("\\$\\{(.*?)\\}");

public static String resolvePlaceholder(Map<String, String> map, String s) {
    StringBuffer sb = new StringBuffer();
    Matcher m = replaceRegex.matcher(s);

    while (m.find()) {
        m.appendReplacement(sb, map.get(m.group(1)));
    }

    m.appendTail(sb);

    return sb.toString();
}
  • Related