3

In java I want to replace only the capturing group in the matched part with some other value and the value to be replaced depends on the capturing group.

Eg:

String str = "fname:hello hello:world ffff:off";
Map<String, String> mapping = new HashMap<String, String>();
dat.put("fname", "meme");
dat.put("hello", "below");
dat.put("ffff", "ssss");
Pattern pat = Pattern.compile("([a-zA-Z_]+):");

In the above code I want to replace the capturing group part of the pattern "pat" with the corresponding mapping found in the "mapping". i.e. After the replacement the "str" string should be transformed to "meme:hello below:world ssss:off" How can I achieve this? Thanks for the help.

Bourne
  • 1,687
  • 11
  • 30
  • 50
  • Per map terms would replace whereever the word occcurs. It might work for my example. So in general I want to replace the capturing group of the matched part with some value which depends on the captured group. – Bourne Apr 16 '14 at 04:00

3 Answers3

4

Please consider bookmarking the Stack Overflow Regular Expressions FAQ for future reference. There's a bunch of Java-specific information in there, particularly in the "Flavor-Specific Information" section.


This works:

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

public class Replacement  {
   public static final void main(String[] ignored)  {

      String str = "fname:hello hello:world ffff:off";
      Map<String, String> mapping = new HashMap<String, String>();
      mapping.put("fname", "meme");
      mapping.put("hello", "below");
      mapping.put("ffff", "ssss");
      Pattern pat = Pattern.compile("([a-zA-Z_]+):");

      Matcher m = pat.matcher(str);


      StringBuffer sb = new StringBuffer();
      while(m.find())  {
         String rplcWith = mapping.get(m.group(1));
         m.appendReplacement(sb, rplcWith + ":");
      }
      m.appendTail(sb);

      System.out.println(sb);
   }
}

Output:

[C:\java_code\]java Replacement
meme:hello below:world ssss:off
Community
  • 1
  • 1
aliteralmind
  • 18,274
  • 16
  • 66
  • 102
1

If you are just trying to match a word if it appears before a :, it is much easier to just create that expression and iterate over the map.

import java.util.*;

public class Main{ 
    public static void main(String[] args) {
        String str = "fname:hello hello:world ffff:off";
        Map<String, String> mapping = new HashMap<String, String>();
        mapping.put("fname", "meme");
        mapping.put("hello", "below");
        mapping.put("ffff", "ssss");

        for (String key: mapping.keySet()) 
            str = str.replace(key + ":", mapping.get(key)+":");
        System.out.println(str);
    }
}

This is simple but sufficient to get your desired output:

meme:hello below:world ssss:off
merlin2011
  • 63,368
  • 37
  • 161
  • 279
  • @PrathikPuthran: This map-iteration is a simpler and more efficient solution than using regex. Is regex required for some reason? It would be nice to have a bit more context. – aliteralmind Apr 16 '14 at 04:02
  • Its simpler but its not the correct solution for Eg if there is a mapping from "me" -> "xyz" then "fname:hello" would be replaced to "fnaxyz:hello" which is not what I want – Bourne Apr 16 '14 at 10:12
  • @PrathikPuthran, The given solution works for the input you provided, but if you require a space before the word to make sure it is sitting alone, that is still cheaper computationally than a regex. – merlin2011 Apr 16 '14 at 17:04
0

You could go through the entrySet of your map and replace all instances of the keys with their associated values

for (Entry<String, String> entry : mapping.entrySet()) {
    str.replaceAll(entry.getKey(), entry.getValue();
}

However, this will have a different output string to what you're expecting because the word "hello" appears twice

So instead of meme:hello below:world ssss:off you will get meme:below below:world ssss:off

Does that answer your question adequately or is it essential that the output is how you defined it?

Eddie Curtis
  • 1,167
  • 6
  • 20
  • Its very essential output is how I desire it to be! – Bourne Apr 16 '14 at 03:58
  • Then you could do `str.replaceAll(entry.getKey() + ":", ":" + entry.getValue());` but that is a bit of a hack so I'd recommend go with a different method :) – Eddie Curtis Apr 16 '14 at 04:01
  • This won't work for my case as it replaces first "hello" even though it does not match regex – Bourne Apr 16 '14 at 04:03
  • 1
    It shouldn't do if you copied it right, as the key is hello and you're concatenating it with ":" so that wouldn't match your first "hello" – Eddie Curtis Apr 16 '14 at 04:04
  • If there is a mapping from "me" to "abc" your solution would replace "fnaabc:hello" instead of the expected "meme:hello" – Bourne Apr 16 '14 at 04:14
  • It should work if you add a `\b` word boundary at the start: `str.replaceAll("\\b" + entry.getKey() + ":", ...`. – aliteralmind Apr 16 '14 at 04:17