Frithjof Frithjof - 6 months ago 60
Java Question

Case-insensitive String Substitutor

I am using org.apache.commons.lang3.text.StrSubstitutor to parse a String. I have it setup similar to this:

StrSubstitutor sub = new StrSubstitutor(messageValues, "&(", ")");
String format = sub.replace("Information: &(killer) killed &(target)!");

This no longer works if I wright the keys in different cases:

"Information: &(KILLER) killed &(TARGET)!"

Is there a way of making the keys for the String Substitutor case-insensitive?

I cannot use
because I only want the keys to be case-insensitive.


StrSubstitutor has a constructor that takes an instance of StrLookup. You can create an implementation of StrLookup that lowercases the keys its looking for before actually looking for them.

Here's how it looks like:

public class CaseInsensitiveStrLookup<V> extends StrLookup<V> {

private final Map<String, V> map;

CaseInsensitiveStrLookup(final Map<String, V> map) { = map;

public String lookup(final String key) {
    String lowercaseKey = key.toLowerCase(); //lowercase the key you're looking for
    if (map == null) {
        return null;
    final Object obj = map.get(lowercaseKey);
    if (obj == null) {
        return null;
    return obj.toString();

Using this StrLookup implementation you don't need to worry about what kind of Map you're passing to the constructor.

The following test case returns succesfully, using the above implementation:

import org.apache.commons.lang3.text.StrSubstitutor;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;

public class TestClass {

public void test() {

    Map<String, String> messageValues = new HashMap<String, String>();
    messageValues.put("killer", "Johnson");
    messageValues.put("target", "Quagmire");
    StrSubstitutor sub = new StrSubstitutor(new CaseInsensitiveStrLookup<String>(messageValues), "&(", ")", '\\');

    String format2 = sub.replace("Information: &(killer) killed &(target)!");
    String format = sub.replace("Information: &(KILLER) killed &(TARGET)!");
    Assert.assertEquals(format, "Information: Johnson killed Quagmire!");
    Assert.assertEquals(format2, "Information: Johnson killed Quagmire!");