解析带分隔符的字符串并将其加载到地图中?

Parse a string with delimiters and load it in a map?

我有以下格式为 key1=value1, key2=value2 的字符串,我需要将其加载到地图 (Map<String, String>) 中作为 key=value,所以我需要用逗号 [=15] 分隔=] 然后加载 cossn 作为键和 0 它的值。

String payload = "cossn=0, abc=hello/=world, Agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";

HashMap<String, String> holder = new HashMap();
String[] keyVals = payload.split(", ");
for(String keyVal:keyVals) {
  String[] parts = keyVal.split("=",2);
  holder.put(parts[0], parts[1]);
}   

我在这一行 holder.put(parts[0], parts[1]); 得到 java.lang.ArrayIndexOutOfBoundsException 并且它发生在这个字符串 Agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36 的 bcoz 因为它在值 KHTML, like Gecko 中有一个额外的逗号。

我该如何解决这个问题?一般来说,下面应该是我在地图中加载后的键和值。

Key         Value
cossn       0
abc         hello/=world
Agent       Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36

鉴于您无法控制负载,您需要采取措施使 "illegal commas" 与您的“,”正则表达式不匹配。

Vampire 提供了一个很棒的正则表达式。由于我已经走上了手动解析的道路,所以我将在下面提供一个非正则表达式的解决方案。

另一种解决方案是通过逐字符迭代并保存子字符串来手动查找 parse/split 点。跟踪 "last comma-space" 直到到达 "next equals" 以确定是否拆分该逗号 - space 或不。

这里有一些代码演示了我要解释的内容。

import java.util.Arrays;

public class ParseTest {

    static String payload = "cossn=0, abc=hello/=world, Agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";

    public static void main(String[] args) {
        int lastCommaSpace = -2;
        int beginIndex = 0;

        // Iterate over string
        // We are looking for comma-space pairs so we stop one short of end of
        // string
        for (int i = 0; i < payload.length() - 1; i++) {
            if (payload.charAt(i) == ',' && payload.charAt(i + 1) == ' ') {
                // This is the point we want to split at
                lastCommaSpace = i;
            }
            if (payload.charAt(i) == '=' && lastCommaSpace != beginIndex - 2) {
                // We've found the next equals, split at the last comma we saw
                String pairToSplit = payload.substring(beginIndex, lastCommaSpace);
                System.out.println("Split and add this pair:" + Arrays.toString(pairToSplit.split("=", 2)));
                beginIndex = lastCommaSpace + 2;
            }
        }
        // We got to the end, split the last one
        String pairToSplit = payload.substring(beginIndex, payload.length());
        System.out.println("Split and add this pair:" + Arrays.toString(pairToSplit.split("=", 2)));
    }

}

正如您所说,您的密钥仅包含字母数字,以下可能是一个很好的拆分启发式方法:

payload.split("\s*,\s*(?=[a-zA-Z0-9_]+\s*=|$)");

这将根据可能的空格框逗号进行拆分,逗号后跟字符串末尾或字母数字键、可选的空格和等号。