使用hashmap值替换String get Error

时间:2017-11-08 17:54:41

标签: java string replace hashmap

我有一个String"abc|a&b")我希望将String的部分替换为其他String。替换存储在HashMap<String, String>中,如下所示:

  1. "a"&gt; "true"
  2. "b"&gt; "false"
  3. "abc"&gt; "true"
  4. 我的结果是"truefalsec|true&false",但我需要"true|true&false"

    我的代码:

    for(Map.Entry<String, String> entry: map.entrySet()) {
        if(expression.contains(entry.getKey()))
            expression = expression.replace(entry.getKey(), entry.getValue());
    }
    System.out.println(expression);
    

    你们有什么建议吗?

3 个答案:

答案 0 :(得分:1)

    String expression = "abc|a&b";

    Map<String, String> map = new LinkedHashMap<>();

    map.put("a", "true");
    map.put("abc", "true");
    map.put("b", "false");

    List<String> parts = Arrays.stream(expression.split("\\W+")).filter(map::containsKey)
            .map(map::get).collect(Collectors.toList());

    Queue<String> separators = new LinkedList<>(Arrays.asList(expression.split("\\w+"))
            .stream().filter(s -> !s.isEmpty())
            .collect(Collectors.toList()));

    StringBuilder result = new StringBuilder();

    for(String part : parts){
        result.append(part).append(!separators.isEmpty() ? separators.poll() : "");
    }

    System.out.println(result.toString());

您可以使用流从表达式获取所有键,然后使用相同的分隔符 - &gt;改变你需要的东西并将整个东西合并回String。

答案 1 :(得分:1)

问题是您重新启动扫描以进行下一次更换,并且首先扫描最短的输入。

a之前扫描abc,您永远不会匹配abc,因为a已被其他内容替换,然后才会扫描abc }。对要扫描的部件进行长度扫描,最长的扫描为commented by rgettman

通过重新启动每个输入的扫描,您可以替换替换值的内容。例如。如果您在b之前扫描ab会被false替换,但a中的false会被{{1}替换导致true开始被b替换。

要修复第二个问题并提高性能,您应该只扫描输入一次。

扫描输入一次,扫描多个文本之一的最简单方法是使用ftruelse之类的正则表达式,即列出由abc|a|b分隔的键,最长键。

假设替换映射可以是任何内容,您应该从|动态构建正则表达式,记住引用地图中的键和值,因此任何特殊字符都不会被视为一个正则表达式的特殊字符,例如匹配任何字符Map

这是使用正则表达式替换循环执行所有操作的方法(在Java 8中):

.

测试

public static String replace(String input, Map<String, String> replacementValues) {
    String regex = replacementValues.keySet().stream()
                   .sorted(Comparator.comparingInt(String::length).reversed()
                                     .thenComparing(Function.identity()))
                   .map(Pattern::quote)
                   .collect(Collectors.joining("|"));
    StringBuffer buf = new StringBuffer(input.length() + 16);
    Matcher m = Pattern.compile(regex).matcher(input);
    while (m.find())
        m.appendReplacement(buf, Matcher.quoteReplacement(replacementValues.get(m.group())));
    return m.appendTail(buf).toString();
}

输出

Map<String, String> map = new HashMap<>(); map.put("a", "true"); map.put("b", "false"); map.put("abc", "true"); System.out.println(replace("abc|a&b", map));

如果扫描应匹配单词而不是子字符串,请将正则表达式编译更改为:

true|true&false

答案 2 :(得分:0)

问题是,您首先要替换ab。然后,abc不会保留,并且不会被替换。您可以使用LinkedHashMap并按照希望替换它们的顺序插入元素。这样可行,因为LinkedHashMap允许您按照插入它们的顺序迭代它们的值,而HashMap将按顺序返回它们,该顺序取决于键hashCode

Map<String, String> map = new LinkedHashMap<>();
map.put("abc", "true");
map.put("a", "true");
map.put("b", "false");

for(Map.Entry<String, String> entry: map.entrySet()) {
    expression = expression.replace(entry.getKey(), entry.getValue());
}
System.out.println(expression);