In Java, I have to insert strings value based on the key in main string. For example -

Main String -

sellers(seller: $sellerId, shipment: $shipmentId)

Map of key and value -

{
    sellerId: abc
    shipmentId: 123
}

So after inserting it will become

sellers(seller: abc, shipment: 123)

I know i can do string replace. But that doesn't seem to be good approach here. So just wondering is there a standard approach or better way of doing things here?

3 Answers

0
Pshemo On Best Solutions

Depending on values map can hold you may face some problems. For instance if value may contain other key identifier like

{
    foo: $bar
    bar: 123
}

then using series of replace(mapEntryKey, mapEntryValue) could change string like

abc $foo efg $bar 

first into $foo->$bar

abc $bar efg $bar

and then $bar->123

abc 123 efg 123

which is NOT what we wanted.

To avoid such problem we should iterate over template only once, search for each $key and replace it with value stored for it in map. If map doesn't contain such key we can leave it as it (replace it with itself).

We can do it with Matcher#replaceAll​(Function<MatchResult,​String> replacer). BTW if map value can contain $ and \ which are also metacharacters in replacement, we need to escape them. To do it we can use Mather#quoteReplacement method.

Demo:

Map<String, String> map = Map.of("sellerId", "abc",
        "shipmentId", "123");
String yourTemplate = "sellers(seller: $sellerId, shipment: $shipmentId)";

Pattern p = Pattern.compile("\\$(\\w+)");
Matcher m = p.matcher(yourTemplate);

String replaced = m.replaceAll(match -> {
    if(map.containsKey(match.group(1))){
        return Matcher.quoteReplacement(map.get(match.group(1)));
    }else{
        return Matcher.quoteReplacement(match.group());
    }
});
System.out.println(replaced);

Output: sellers(seller: abc, shipment: 123).

1
ernest_k On

Two approaches you can consider:

1 - loop over map entries, and do a simple string replace (note that this assumes a single occurrence of each var in the strings; if that is not the case, you need to use replaceAll):

String text = "sellers(seller: $sellerId, shipment: $shipmentId)";
Map<String, Object> binding = ...;

String result = text;
for (Entry<String, Object> entry : binding.entrySet()) {
    result = result.replace("$" + entry.getKey(), String.valueOf(entry.getValue()));
}

2 - for advanced use cases, you want to use a proper template engine. And here's an example using groovy's simple template engine (use in java by adding the groovy jar):

groovy.text.SimpleTemplateEngine engine = new groovy.text.SimpleTemplateEngine();
Writable template = engine.createTemplate(text).make(binding);

String result = template.toString();

Just note that groovy replaces variable names prefixed with $, and that's why this works without changes (making this a good choice for your current syntax).

Both produce your expected result, but you have to choose based on what this can turn into.

0
Community On

String format is an option here

Map<String, Integer> yourMap = new HashMap<>();
yourMap.put("abc", 123);

for (Map.Entry<String, Integer> entry : yourMap.entrySet()) {
   String output = String.format("sellers(seller: %s, shipment: %d)", entry.getKey(), entry.getValue());
   System.out.println("output = " + output);
}