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

时间:2017-09-21 20:11:18

标签: java hashmap guava splitter

我有一个特殊格式的字符串,所以我想将该字符串解析为map。我有一个下面的方法,它将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中使用相同的值两次相同的键时,我的上述方法失败并抛出异常。例如,对于下面的字符串,它不起作用,它失败然后返回空映射,因为它有两次type键。

"type=3|Id=23456|user=13456|type=3"

我该怎么做才能修复此问题而不是修复字符串有效负载?因此,假设相同的密钥多次出现,则覆盖映射中的该键值而不是失败。我想要返回一张Mutable地图。

我仍在使用Java 7.执行此操作的最佳和有效方法是什么?

2 个答案:

答案 0 :(得分:1)

我不知道在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;
}

答案 1 :(得分:0)

文档说如果有重复的密钥,split会抛出异常:

  

@CheckReturnValue公共地图拆分(CharSequence   序列)

     

将序列拆分为子字符串,将每个子字符串拆分为一个条目,   并返回每个条目的不可修改的映射。例如,   Splitter.on( ';')trimResults()withKeyValueSeparator( “=&gt;” 中)。   .split(“a =&gt; b; c =&gt; b”)将返回从“a”到“b”和“c”的映射到   湾

     

返回的地图保留了序列中条目的顺序。

     

抛出:       IllegalArgumentException - 如果指定的序列未拆分为有效的映射条目,或者存在重复的键

所以,你不能使用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));