将格式化字符串解析为多次具有相同键的映射?
Parse a formatted string into a map which has same key many times?
我有一个以特定格式出现的字符串,所以我想将该字符串解析为映射。我有一个将 String 解析为 Map 的以下方法,它工作正常。
public static Map<String, String> parseStringToMap(String payload) {
try {
return Maps.newHashMap(Splitter.on("|").withKeyValueSeparator("=").split(payload));
} catch (Exception ex) {
return ImmutableMap.of();
}
}
字符串示例:
"type=3|Id=23456|user=13456"
现在有时当我在同一个字符串 payload
中两次使用相同的键和相同的值时,我的上述方法会失败并抛出异常。例如,对于下面的字符串,它不起作用并且失败,然后它 return 是空映射,因为它有两次 type
键。
"type=3|Id=23456|user=13456|type=3"
除了修复字符串负载,我还能做些什么来解决这个问题?因此,假设相同的键出现多次,则覆盖映射中的该键值而不是失败。我想 return 返回一个可变映射。
我仍在使用 Java 7. 最好和最有效的方法是什么?
我不知道在 Guava 中有什么方法可以做到这一点,但是用普通的旧方法做起来并不难 Java:
Map<String, String> map = new HashMap<>();
for (String part : payload.split("\|")) {
String[] subparts = part.split("=", 2);
map.put(subparts[0], subparts[1]);
}
return map;
如果你只想检查字符串的格式是否正确(即有管道分隔的元素,每个元素包含一个 =
符号),那么你可以只使用 indexOf
找到这些:
int start = 0;
while (start < payload.length()) {
int end = payload.indexOf('|', start);
if (end == -1) {
end = payload.length();
}
int equalsPos = payload.indexOf('=', start);
if (equalsPos > end || equalsPos < 0) {
// No = found between adjacent |s. Not valid format.
return Collections.emptyMap();
}
// Extract the substrings between | and =, and = and the next |.
map.put(payload.substring(start, equalsPos), payload.substring(equalsPos + 1, end));
start = end + 1;
}
文档说如果有重复的键,split 将抛出异常:
@CheckReturnValue public Map split(CharSequence
sequence)
Splits sequence into substrings, splits each substring into an entry,
and returns an unmodifiable map with each of the entries. For example,
Splitter.on(';').trimResults().withKeyValueSeparator("=>")
.split("a=>b ; c=>b") will return a mapping from "a" to "b" and "c" to
b.
The returned map preserves the order of the entries from sequence.
Throws:
IllegalArgumentException - if the specified sequence does not split into valid map entries, or if there are duplicate keys
所以,您不能使用 MapSplitter 的拆分,抱歉!
与Java 8:
return Splitter
.on("|")
.splitToList(payload)
.stream()
.map(kv -> kv.split("="))
.collect(Collectors.toMap(kv -> kv[0], kv -> kv[1], (d1, d2) -> d1));
我有一个以特定格式出现的字符串,所以我想将该字符串解析为映射。我有一个将 String 解析为 Map 的以下方法,它工作正常。
public static Map<String, String> parseStringToMap(String payload) {
try {
return Maps.newHashMap(Splitter.on("|").withKeyValueSeparator("=").split(payload));
} catch (Exception ex) {
return ImmutableMap.of();
}
}
字符串示例:
"type=3|Id=23456|user=13456"
现在有时当我在同一个字符串 payload
中两次使用相同的键和相同的值时,我的上述方法会失败并抛出异常。例如,对于下面的字符串,它不起作用并且失败,然后它 return 是空映射,因为它有两次 type
键。
"type=3|Id=23456|user=13456|type=3"
除了修复字符串负载,我还能做些什么来解决这个问题?因此,假设相同的键出现多次,则覆盖映射中的该键值而不是失败。我想 return 返回一个可变映射。
我仍在使用 Java 7. 最好和最有效的方法是什么?
我不知道在 Guava 中有什么方法可以做到这一点,但是用普通的旧方法做起来并不难 Java:
Map<String, String> map = new HashMap<>();
for (String part : payload.split("\|")) {
String[] subparts = part.split("=", 2);
map.put(subparts[0], subparts[1]);
}
return map;
如果你只想检查字符串的格式是否正确(即有管道分隔的元素,每个元素包含一个 =
符号),那么你可以只使用 indexOf
找到这些:
int start = 0;
while (start < payload.length()) {
int end = payload.indexOf('|', start);
if (end == -1) {
end = payload.length();
}
int equalsPos = payload.indexOf('=', start);
if (equalsPos > end || equalsPos < 0) {
// No = found between adjacent |s. Not valid format.
return Collections.emptyMap();
}
// Extract the substrings between | and =, and = and the next |.
map.put(payload.substring(start, equalsPos), payload.substring(equalsPos + 1, end));
start = end + 1;
}
文档说如果有重复的键,split 将抛出异常:
@CheckReturnValue public Map split(CharSequence sequence)
Splits sequence into substrings, splits each substring into an entry, and returns an unmodifiable map with each of the entries. For example, Splitter.on(';').trimResults().withKeyValueSeparator("=>") .split("a=>b ; c=>b") will return a mapping from "a" to "b" and "c" to b.
The returned map preserves the order of the entries from sequence.
Throws: IllegalArgumentException - if the specified sequence does not split into valid map entries, or if there are duplicate keys
所以,您不能使用 MapSplitter 的拆分,抱歉!
与Java 8:
return Splitter
.on("|")
.splitToList(payload)
.stream()
.map(kv -> kv.split("="))
.collect(Collectors.toMap(kv -> kv[0], kv -> kv[1], (d1, d2) -> d1));