不区分大小写的字符串替代者

时间:2014-04-07 17:38:25

标签: java string apache formatting key-value

我使用org.apache.commons.lang3.text.StrSubstitutor来解析String。我有类似的设置:

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

如果我在不同情况下使用密钥,则此功能不再有效:

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

有没有办法为String Substitutor 不区分大小写制作密钥?

我无法使用toLowerCase(),因为我只希望密钥不区分大小写。

4 个答案:

答案 0 :(得分:3)

StrSubstitutor有一个构造函数,它接受一个StrLookup实例。您可以创建一个StrLookup实现,在实际查找它们之前降低其查找的键。

以下是它的样子:

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

private final Map<String, V> map;

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

@Override
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();
}
}

使用此StrLookup实现,您无需担心要传递给构造函数的Map类型。

以下测试用例使用上述实现成功返回:

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

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

@Test
public class TestClass {

@Test
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!");
}
}

答案 1 :(得分:3)

您不需要编写自定义类。假设您可以使用日志( n )访问时间,只需使用不区分大小写的TreeMap。

public static void main(String[] args) {
    Map<String, String> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    m.put("foo", "bar");
    StrSubstitutor sub = new StrSubstitutor(m);
    String s = sub.replace("${FOO}");
    System.out.println(s);
} // prints "bar"

答案 2 :(得分:1)

我认为这个不区分大小写的地图会起作用:

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

public class CaseMap<V> extends HashMap<String, V> {
    public CaseMap() {
    }

    public CaseMap(int capacity) {
        super(capacity);
    }

    public CaseMap(int capacity, float loadFactor) {
        super(capacity, loadFactor);
    }

    public CaseMap(Map<String, ? extends V> map) {
        putAll(map);
    }

    public V put(String key, V value) {
        return super.put(key.toUpperCase(), value);
    }

    public V get(Object key) {
        if (!(key instanceof String)) return null;
        return super.get(((String)key).toUpperCase());
    }
}

如果您不控制messageValues地图的创建,您可以像这样构建一个CaseMap:

CaseMap<String> caseFreeMessageValues = new CaseMap<String>(messageValues);

然后像这样构建你的StrSubstitutor:

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

您可能想要考虑应该覆盖的Map的其他方法,例如containsKey

答案 3 :(得分:0)

如果你需要灵活性,Map和Tokens都不区分大小写并且你无法控制正在构建的地图,你可以使用这样的东西。

String replaceTokens(String str, Map<String, String> messageValues) {
    if(tokenToValue == null || tokenToValue.size() < 1) return str;
    StrSubstitutor caseInsensitiveTokenReplacer = new StrSubstitutor(new CaseInsensitiveStrLookup<>(messageValues),
                                                                     "&(", ")", '\\');
    return caseInsensitiveTokenReplacer.replace(str);
}
  

StrLookup实施

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

private final Map<String, V> map = new TreeMap<String, V>(String.CASE_INSENSITIVE_ORDER);

public CaseInsensitiveStrLookup(final Map<String, V> map) throws NullValueKeyNotSupported {
    if(map.containsKey(null)) throw new Exception(); // Dont want to support null 
    this.map.putAll(map);
}

@Override
public String lookup(final String key) {
    V value = map.get(key);
    if(value == null) return null;
    return value.toString();
}}