2

I am trying to parse an expression to find out some reserved operators/strings and replace them with corresponding numeric values , which are stored in a hashmap, and display the resultant expression which has numeric values instead of the reserved strings. This is what I am trying to do:

String expression = "SUM_ALL(4:5,5:6)>MAX(6:7)";
Map<String, Double> functionOperators = new HashMap<String,Double>();
functionOperators.put("SUM_ALL(4:5,5:6)", 4.0);
functionOperators.put("MAX(6:7)",5.0);

expression = expression.replaceAll("(SUM_ALL|MAX)\\s*\\(\\s*([\\d:,]+)\\s*\\)",
            Double.toString(functionOperators.get(String.format("%s(%s)","$1","$2"))));
System.out.println(expression);

"$1" and "$2" are used to back reference the groups in the expression.

Here is the output of the same:

Exception in thread "main" java.lang.NullPointerException

whereas when I remove the fetching part (from the hashmap) and instead limit it to just a string change using the back-referenced groups, it works just fine.

expression = expression.replaceAll("(SUM_ALL|MAX)\\s*\\(\\s*([\\d:,]+)\\s*\\)",
            String.format("%s|%s|","$1","$2"));

Output:

SUM_ALL|4:5,5:6|>MAX|6:7|

I suspect that while fetching the value from the hashmap, the "$1" and "$2" variables have still not been resolved by back-referencing and hence, it is not able to locate a key corresponding to the same.

If this is true, then what method do you suggest to implement my use case where I need the replacement value from a predefined hashmap.

Abhishek Jain
  • 4,478
  • 8
  • 34
  • 51
  • @JanDvorak yes it does here is the function from javadocs _replaceAll(String regex, String replacement)_ – Bhavik Shah Oct 26 '12 at 12:22
  • @JanDvorak - It does. Please consider my second example where it is working fine. – Abhishek Jain Oct 26 '12 at 12:22
  • in first String.format("%s(%s)","$1","$2") you have used brackets and in 2nd example you have used |%s| – Bhavik Shah Oct 26 '12 at 12:24
  • @BhavikShah - That is just for the sake of clarity in the 2nd example. It works fine with brackets as well. – Abhishek Jain Oct 26 '12 at 12:26
  • im sorry im not good with regex is the output of _String.format("%s|%s|","$1","$2")_ is $1($2) ? – Bhavik Shah Oct 26 '12 at 12:37
  • @BhavikShah - You didn't get my point. $1 will backreference to group 1 in the regex which is SUM_ALL or MAX, and $2 will backreference to group 2 in the regex which is . String.format only replaces the %s with the values listed in further arguments. – Abhishek Jain Oct 26 '12 at 13:13

2 Answers2

2

I dont know what volume of dat you have but it seems the problem is replaceAll that is not working properly because I've tried with replace and it works awesome.

String expression = "SUM_ALL(4:5,5:6)>MAX(6:7)<SUM_ALL(4:5,5:6)";
String mat = "";
Map<String, Double> functionOperators = new HashMap<String,Double>();
functionOperators.put("SUM_ALL(4:5,5:6)", 4.0);
functionOperators.put("MAX(6:7)",5.0);
Matcher m = 
    Pattern.compile(
            "(?:(SUM_ALL|MAX|MIN)\\(((?:\\d+:\\d+,?){1,2})\\)[+-><\\*/]?)")
            .matcher(expression);
while (m.find()) {
    mat = String.format("%s(%s)", m.group(1), m.group(2));
    expression = expression.replace(mat, functionOperators.get(mat).toString());
}
System.out.println(expression);

Was taken directly from your earlier example (yesterday)

Javier Diaz
  • 1,791
  • 1
  • 17
  • 25
  • Thanks for the answer. I was actually looking around for simpler ways of doing the same but this looks reasonable. Thanks again. – Abhishek Jain Oct 26 '12 at 13:20
1

Your second example works because the return value of String.format("%s(%s)","$1","$2") is "$1($2)", which is a valid second argument to the replaceAll method. However, when you pass "$1($2)" to the get method of your map, it returns null.

To make this work, I think you'd need to separate the matching, mapping, and replacement operations.

  • Get a list of all matches of your regular expression (see Create array of regex matches).
  • Get the corresponding numeric value of each match out of the map.
  • Call replaceAll on each match.
Community
  • 1
  • 1
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • I agree with your explanation on where the problem lies but the solution seems a little complicated. The answer by Javier looks a little more intuitive though. :) – Abhishek Jain Oct 26 '12 at 13:19
  • @AbhishekJain No problem. Javier's solution is doing basically the same, but he's processing each match as he finds them. I agree, that is simpler than building a list. – Bill the Lizard Oct 26 '12 at 13:22