Java RegEX: parse and extract dollar sign variables from string








Problem:

extract variables in the form of ${var} in string. e.g. "a ${b} ${c} ${b}", where b and c are variable names.

Solution:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class QueryPattern {

 private String _s;
 private List<String> _vars;

 public QueryPattern(String s) {
  _s = s;
  _vars = parseVariables(s);
 }

 public List<String> variables() {
  return _vars;
 }

 @Override
 public String toString() {
  return _s;
 }

 public String evaluate(Map<String, String> varMap) throws Throwable {
  return evaluate(this, varMap);
 }

 public String evaluate(String[] vars) throws Throwable {
  return evaluate(this, vars);
 }

 public static void main(String[] args) throws Throwable {
  QueryPattern p = new QueryPattern("a \\\\\\${b} ${c}");
  System.out.println(p);
  System.out.println(p.evaluate(new String[] { "b", "1", "c", "2" }));
 }

 public static List<String> parseVariables(String s) {
  List<String> vars = new ArrayList<String>();
  Pattern p = Pattern.compile("\\$\\{[a-zA-Z]+\\w*\\}");
  Matcher m = p.matcher(s);
  while (m.find()) {
   int n = 0;
   for (int i = m.start()-1; i >= 0 && s.charAt(i) == '\\'; i--) {
    n++;
   }
   if (n % 2 != 0) {
    continue;
   }
   String var = s.substring(m.start() + 2, m.end() - 1);
   if (!vars.contains(var)) {
    vars.add(var);
   }
  }
  if (!vars.isEmpty()) {
   return vars;
  }
  return null;
 }

 public static String evaluate(QueryPattern pattern, Map<String, String> varMap) throws Throwable {
  List<String> vars = pattern.variables();
  String s = pattern.toString();
  if (vars == null) {
   return s;
  }
  for (String var : vars) {
   String value = varMap.get(var);
   if (value == null) {
    throw new Exception("Could not find value for variable: " + var);
   }
   s = s.replaceAll("\\$\\{" + var + "\\}", value);
  }
  return s;
 }

 public static String evaluate(String pattern, Map<String, String> varMap) throws Throwable {
  return evaluate(new QueryPattern(pattern), varMap);
 }

 public static String evaluate(QueryPattern pattern, String[] vars) throws Throwable {
  if (vars.length < 2 || vars.length % 2 != 0) {
   throw new Exception("Invalid length of array. Should be in the form of {\"name\", \"value\"}.");
  }
  Map<String, String> varMap = new HashMap<String, String>(vars.length / 2);
  for (int i = 0; i < vars.length; i += 2) {
   varMap.put(vars[i], vars[i + 1]);
  }
  return evaluate(pattern, varMap);
 }

 public static String evaluate(String pattern, String[] vars) throws Throwable {
  return evaluate(new QueryPattern(pattern), vars);
 }
}



No comments:

Post a Comment