[英]Use hashmap value to replace String get Error
我有一個String
( "abc|a&b"
),我想更換的零件String
與其他String
秒。 替換項存儲在HashMap<String, String>
中,如下所示:
"a"
> "true"
"b"
> "false"
"abc"
> "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);
你們有什么建議嗎?
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());
您可以使用流從表達式中獲取所有鍵,然后對分隔符使用相同的鍵->更改所需內容,然后將整個內容合並回String。
問題是您重新開始掃描以進行下一個替換,並且首先掃描了最短的輸入。
通過掃描a
之前的abc
,您將永遠不會匹配abc
,因為在掃描abc
之前a
已經被別的東西替代了。 按照rgettman的評論,對要掃描的部分按長度進行排序,以最長的為准 。
通過重新啟動每個輸入的掃描,您可以替換替換值的內容。 例如,如果您掃描b
前a
, b
被換成false
,但隨后的a
在false
被替換為true
,導致b
開始替換ftruelse
。
要解決第二個問題並提高性能,您應該只掃描一次輸入。
掃描輸入一次(掃描多個文本之一)的最簡單方法是使用正則表達式,例如abc|a|b
,即列出用|
分隔的鍵|
,最長的鍵在前。
假設替換映射可以是任何東西,您應該從Map
動態構建正則表達式,記住要在Map
同時引用鍵和值,因此任何特殊字符都不會被視為正則表達式特殊字符,例如match-任何字符.
。
這是使用regex替換循環執行所有操作的方法(在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
如果掃描應匹配單詞而不是子字符串,請將正則表達式編譯更改為:
Pattern.compile("\\b(?:" + regex + ")\\b")
問題是,您首先要替換a
或b
。 然后,不會保留abc
,也不會被替換。 您可以使用LinkedHashMap
並按希望替換的順序插入元素。這是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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.