4

I need your help for one tricky problem. I have one map like below

Map<Integer, String> ruleMap = new HashMap<>();
ruleMap.put(1, "A");
ruleMap.put(12, "Test - 12");
ruleMap.put(1012, "Test Metadata 12 A");

and I have one rule in which I am separating ids and collecting them into a list. By iterating over the list, I am replacing its ids by its respective value from map.

code :

String rule = "1 AND 12 OR 1012 AND 12 or 1012";

List < String > idList = new ArrayList < > ();

Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(rule);
while (m.find()) {
    idList.add(m.group());
}
for (String id: idList) {
    if (ObjectUtils.isNonEmpty(ruleMap.get(Integer.parseInt(id)))) {
        rule = rule.replaceFirst(id, ruleMap.get(Integer.parseInt(id)));
    }
}
System.out.println(rule);

I am getting output like this -

A AND Test - Test - 12 OR Test Metadata 12 A AND 12 or Test Metadata 12 A

as you can see for the first iteration of id 12 replaced its respected value but on the second occurrence of the id 12 replaced the value Test - 12 to Test - Test - 12.

So can anyone help me with this?

2 Answers 2

4

You need to be doing regex replacement with proper word boundaries. I suggest using a regex iterator (as you were already doing), but use the pattern \b\d+\b to match only full number strings. Then, at each match, do a lookup in the rule map, if the number be present, to find a replacement value. Use Matcher#appendReplacement to build out the replacement string as you go along.

Map<String, String> ruleMap = new HashMap<>();
ruleMap.put("1", "A");
ruleMap.put("12", "Test - 12");
ruleMap.put("1012", "Test Metadata 12 A");

String rule = "1 AND 12 OR 1012 AND 12 or 1012";

Pattern pattern = Pattern.compile("\\b\\d+\\b");
Matcher m = pattern.matcher(rule);
StringBuffer buffer = new StringBuffer();
  
while(m.find()) {
    if (ruleMap.containsKey(m.group(0))) {
        m.appendReplacement(buffer, ruleMap.get(m.group(0)));
    }
}

m.appendTail(buffer);

System.out.println(rule + "\n" + buffer.toString());

This prints:

1 AND 12 OR 1012 AND 12 or 1012
A AND Test - 12 OR Test Metadata 12 A AND Test - 12 or Test Metadata 12 A
Sign up to request clarification or add additional context in comments.

7 Comments

You need to at least give me some context here if you want debugging help.
I think my rule map contains any special characters like $ or #% or ( ) which causing this error.
I know how to fix this, but you're really asking a different question now.
sorry, Tim but can you tell me what causes this kind of error. like I have checked but I don't have any special characters in my rule map. so is there any other possibilities which causing this error?
You need to regex escape the search terms using Pattern#quote. But again, the question you actually asked above searches for only numbers. I suggest opening a new question if you can't resolve it on your own.
|
1

If you happen to use Java 9 or higher you could also use Matcher#replaceAll:

Map<Integer, String> ruleMap = new HashMap<>();
ruleMap.put(1, "A");
ruleMap.put(12, "Test - 12");
ruleMap.put(1012, "Test Metadata 12 A");

String rule = "1 AND 12 OR 1012 AND 12 or 1012";

rule = Pattern.compile("\\b\\d+\\b")
        .matcher(rule)
        .replaceAll(m -> ruleMap.getOrDefault(
                Integer.parseInt(m.group()), m.group()));

System.out.println(rule);

1 Comment

@TimBiegeleisen Thank you for pointing that out. I'll add Map.getOrDefault to address that issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.