【问题标题】:Replace a map of values in string替换字符串中的值映射
【发布时间】:2021-09-23 16:59:57
【问题描述】:

假设我有一个String text = "abc",我想替换一个值映射,例如:

a->b
b->c
c->a

你会怎么做?

因为很明显:

map.entrySet().forEach(el -> text = text.replaceAll(el.getKey(), el.getValue()))

行不通,因为第二次替换也会覆盖第一次替换(最后你不会得到bca

那么你将如何避免这种“替换之前的替换”?

我看到了this answer,但我希望有一个更简洁和天真的解决方案(希望不使用 Apache 外部包)

顺便说一下字符串也可以是多个字符

【问题讨论】:

  • a, b, c 是字符串还是字符?
  • 地图的类型是什么? Map<Character, Character>Map<String, String>?
  • 大家好,抱歉耽搁了,“字符串映射”,所以Map<String, String>
  • 如果映射是字符串到字符串,“替换”操作取决于顺序。地图是NavigableMap 吗?如果没有,如何订购确定?
  • @Bohemian 好点......为了这个例子,它不相关的顺序(但是是的,它依赖于顺序)..你可能会想List<Pair<String, String>>,所以顺序是该对在列表中的位置

标签: java string algorithm replace


【解决方案1】:

我想出了这个使用 java 流的解决方案。

String text = "abc";
Map<String, String> replaceMap = new HashMap<>();
replaceMap.put("a", "b");
replaceMap.put("b", "c");
replaceMap.put("c", "a");

System.out.println("Text = " + text);

text = Arrays.stream(text.split("")).map(x -> {
    String replacement = replaceMap.get(x);
    if (replacement != null) {
        return x.replace(x, replacement);
    } else {
        return x;
    }
}).collect(Collectors.joining(""));

System.out.println("Processed Text = " + text);

输出

Text = abc
Processed Text = bca

【讨论】:

  • 这看起来不能处理要替换的字符串长于一个字符的情况(因为它使用text.split(""))。
  • 是的。 PO没有提到他想映射单词。我精心设计了这个答案来满足给定的要求。
  • 嗨,感谢您的回答,但这仅适用于示例,但字符串也可以长于一个字符
【解决方案2】:

这是我正常处理正则表达式替换的问题。 Java 中的代码有点冗长,但这应该可以工作:

String text = "abc";
Map<String, String> map = new HashMap<>();
map.put("a", "b");
map.put("b", "c");
map.put("c", "a");

String regex = map.keySet()
                  .stream()
                  .map(s -> Pattern.quote(s))
                  .collect(Collectors.joining("|"));

String output = Pattern.compile(regex)
                       .matcher(text)
                       .replaceAll((m) -> {
                           String s = m.group();
                           String r = map.get(s);
                           return r != null ? r : s;
                       });
System.out.println(output); 
// bca

它相对简单,虽然有点冗长,因为 Java。首先,创建一个接受映射中任何键的正则表达式(使用Pattern.quote() 清理它们),然后在找到实例时使用 lambda 替换从映射中提取适当的替换。

性能密集型部分只是首先编译正则表达式;替换本身应该只通过字符串一次。

应该兼容 Java 1.9+

【讨论】:

    【解决方案3】:

    从 Java 8 开始,有一个称为 chars 的方法返回一个 IntStream,您可以从中获取与该字符表示的整数对应的字符,并使用您的映射对其进行映射。

    如果您的映射是字符串到字符串映射,那么您可以使用:

    text = text.chars().mapToObj(el -> map.get(String.valueOf((char)el))).
                                                     collect(Collectors.joining(""));
    

    如果您的地图是字符到字符,则只需删除 String.valueOf()

    text = text.chars().mapToObj(el -> map.get((char)el)).collect(Collectors.joining(""));
    

    【讨论】:

    • 嗨,感谢您的回答和您的时间,但这仅适用于示例,但字符串也可以长于一个字符
    猜你喜欢
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多