我有一个String
("abc|a&b"
)我希望将String
的部分替换为其他String
。替换存储在HashMap<String, String>
中,如下所示:
"a"
&gt; "true"
"b"
&gt; "false"
"abc"
&gt; "true"
我的结果是"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);
你们有什么建议吗?
答案 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
之前扫描a
,b
会被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)
问题是,您首先要替换a
或b
。然后,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);