Search code examples
javahashmapguavasplitter

Parse a formatted string into a map which has same key many times?


I have a String which is coming in particular format so I want to parse that string into map. I have a below method which parses String to a Map and it works fine.

  public static Map<String, String> parseStringToMap(String payload) {
    try {
      return Maps.newHashMap(Splitter.on("|").withKeyValueSeparator("=").split(payload));
    } catch (Exception ex) {
      return ImmutableMap.of();
    }
  }

Sample example of a string:

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

Now sometimes when I have same key twice with same value in the same String payload, then my above method fails and it throws exception. For example for below string, it doesn't work and it fails and then it returns empty map because it has type key twice.

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

What can I do to fix this instead of fixing the string payload? So let's say if same key comes many times, then overwrite that key value in the map instead of failing. And I want to return a Mutable map back.

I am still working with Java 7. What is the best and efficient way to do this?


Solution

  • I don't know of a way to do it in Guava, but it's not too hard to do with plain old 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;
    

    If you want to check just that the string is in the right format (i.e. there are pipe-separated elements, each containing an = sign), then you can just use indexOf to find these:

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