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

Java 将格式化字符串解析为多次具有相同键的映射?,java,hashmap,guava,splitter,Java,Hashmap,Guava,Splitter,我有一个特殊格式的字符串,所以我想将该字符串解析为map。我有一个下面的方法,它可以将字符串解析成一个映射,并且效果很好 public static Map<String, String> parseStringToMap(String payload) { try { return Maps.newHashMap(Splitter.on("|").withKeyValueSeparator("=").split(payload)); } catch

我有一个特殊格式的字符串,所以我想将该字符串解析为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

"type=3|Id=23456|user=13456|type=3"
我可以做些什么来解决这个问题,而不是解决字符串负载?假设同一个键多次出现,则在映射中覆盖该键值,而不是失败。我想返回一个可变映射


我仍然在使用Java7。最有效的方法是什么?

我不知道用番石榴做这件事的方法,但用普通的旧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;

文档说明,如果存在重复的密钥,split将引发异常:

@CheckReturnValue公共映射拆分(CharSequence 顺序)

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

返回的映射保留了序列中条目的顺序

抛出: 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));

你能使用Java8吗?如果是这样,您可以使用分组收集器来构建
映射
,或类似的。@AndyTurner不幸的是,我仍然使用Java 7,还不能使用Java 8。通过这种方式,我如何检查它们是否仅为该格式?如果它们不是该格式,则返回空映射?或者我应该用try-catch把它包装起来,如果它们不是那种格式并且基于返回的空映射,它会自动抛出异常吗?你说的“不是那种格式”是什么意思?是否有一个
=
,然后是一个
|
,然后是一个
=
等,中间有字符?当然:只需使用indexof搜索字符串中的内容。是的,它必须是此格式,如果不是,则返回空映射。我尝试了您对此有效负载的编辑建议,该负载的格式无效
type=3:Id=23456 | user=13456 | type=3
,并且它不会返回空映射,因为它认为这是一个有效字符串。这不是以什么方式有效吗?它在所有管道之间有一个等号(/字符串的开始和结束)。第一个值中有多个等号并不自动使其无效;这正是你(未说明)的要求。如果这是您想要的,那么为什么不尝试修改此代码呢?这不是一个很难的改变。是的,那么除了Splitter之外还有更好的方法吗?@user1950349也许你可以先用正则表达式修复你的输入?不幸的是,我仍然使用Java 7。
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;
}
    return Splitter
        .on("|")
        .splitToList(payload)
        .stream()
        .map(kv -> kv.split("="))
        .collect(Collectors.toMap(kv -> kv[0], kv -> kv[1], (d1, d2) -> d1));