Java: How to fill placeholders in a text with Map<String,String>?

Viewed 2326

I am working with a code where I want fill several string place holders with another strings. This is the example text I have used to test my code.

String myStr = "Media file %s of size %s has been approved"

This is how I fill the place holders. Since I expect to use several place holders I have used java Map<>.

Map<String, String> propMap = new HashMap<String,String>();
propMap.put("file name","20mb");
String newNotification = createNotification(propMap);

I used following method to create the string.

public String createNotification(Map<String, String> properties){
    String message = ""; 
    message = String.format(myStr, properties);

    return message;
}

How do I replace two of '%s' with "file name" and "20mb"?

5 Answers

Your approach to String#format is wrong.

It expects a variable amount of objects to replace the placeholders as the second argument, not a map. To group them all together, you can use an array or a list.

String format = "Media file %s of size %s has been approved";

Object[] args = {"file name", "20mb"};
String newNotification = String.format(format, args);

That's not what a Map is intended to do. What you add is an entry "file name" -> "20 mb", which basically means the property "file name" has the value "20 mb". What you are trying to do with it is "maintain a tuple of items".

Note that the formatting string has a fixed amount of placeholder; you want a data structure that contains exactly the same amount of items; so essentially an array or a List.

Thus, what you want to have is

public String createNotification(String[] properties) {
    assert(properties.length == 2); // you might want to really check this, you will run into problems if it's false
    return String.format("file %s has size %s", properties);
}

If you want to create notifications of all items in a map, you need to do something like this:

Map<String,String> yourMap = //...
for (Entry<String,String> e : yourMap) {
    System.out.println(createNotification(e.getKey(), e.getValue()));
}

You can simply do this formatting using var-args:

    String myStr = "Media file %s of size %s has been approved";

    String newNotification = createNotification(myStr, "file name", "20mb");

    System.out.println(newNotification);

Pass var-args in createNotification method, here is the code:

public static String createNotification(String myStr, String... strings){
    String message = ""; 
    message=String.format(myStr, strings[0], strings[1]);

    return message;
}

I think %s is Python’s grammar to place holder, can’t use this in Java environment; and your method createNotification() defined needs two parameters, can’t only give one.

After trying several ways finally found a good solution. Place holders must be like this [placeholder] .

public String createNotification(){
    Pattern pattern = Pattern.compile("\\[(.+?)\\]");
    Matcher matcher = pattern.matcher(textTemplate);
    HashMap<String,String> replacementValues = new HashMap<String,String>();
    StringBuilder builder = new StringBuilder();
    int i = 0;
    while (matcher.find()) {
        String replacement = replacementValues.get(matcher.group(1));
        builder.append(textTemplate.substring(i, matcher.start()));
        if (replacement == null){ builder.append(matcher.group(0)); }      
        else { builder.append(replacement); }     
        i = matcher.end();
    }
    builder.append(textTemplate.substring(i, textTemplate.length()));
    return builder.toString()
}
Related