将格式化字符串解析为多次具有相同键的映射?

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));