【问题标题】:Regex to extract key-value pairs separated by space, with space in values正则表达式提取由空格分隔的键值对,值中有空格
【发布时间】:2015-03-23 17:42:08
【问题描述】:

假设一个包含多个连续键值对的单行字符串,以空格分隔,但值中也允许空格(不在键中),例如

key1=one two three key2=four key3=five six key4=seven eight nine ten

从上面正确提取键值对将产生以下映射:

"key1", "one two"
"key2", "four"
"key3", "five six"
"key4", "seven eight nine ten"

其中“keyX”可以是任何字符序列,不包括空格。

尝试一些简单的事情,比如

([^=]+=[^=]+)+

或类似的变化是不够的。

是否有一个正则表达式可以完全处理这种提取,而不需要任何进一步的字符串处理?

【问题讨论】:

  • 试试 ([^= ]+=[^=]+ *)+
  • 我试过了,还是不行。查看其他答案。谢谢。

标签: java regex key-value keyvaluepair


【解决方案1】:

试试lookahead:

(\b\w+)=(.*?(?=\s\w+=|$))

作为 Java 字符串:

"(\\b\\w+)=(.*?(?=\\s\\w+=|$))"

Test at regex101.com; Test at regexplanet(点击“Java”)

【讨论】:

    【解决方案2】:

    \1 包含键,\2 包含值:

    (key\d+)=(.*?)(?= key\d+|$)
    

    在 Java 中使用 \\ 转义 \:

    (key\\d+)=(.*?)(?= key\\d+|$)
    

    演示:https://regex101.com/r/dO8kM2/1

    【讨论】:

    • “key”字符串只是一个占位符名称。键可以有任何值,没有空格。它不起作用,但即使您不修改它也会 +1。谢谢。
    • 我看到了 Johny5 的答案,它更好,正是您想要的,所以我决定不编辑我的答案。 ;)
    • 当然。说得通。 :-)
    【解决方案3】:

    而不是正则表达式,我建议你使用indexOf解析它。类似的,

    String in = "key1=one two three key2=four key3=five six "
            + "key4=seven eight nine ten";
    Map<String, String> kvp = new LinkedHashMap<>();
    int prev = 0;
    int start;
    while ((start = in.indexOf("key", prev)) != -1) {
        // Find the next "=" sign.
        int eqlIndex = in.indexOf("=", start + 3);
        // Find the end... maybe the end of the String.
        int end = in.indexOf("key", eqlIndex + 1);
        if (end == -1) {
            // It's the end of the String.
            end = in.length();
        } else {
            // One less than the next "key"
            end--;
        }
        kvp.put(in.substring(start, eqlIndex),
                in.substring(eqlIndex + 1, end).trim());
        prev = start + 3;
    }
    for (String key : kvp.keySet()) {
        System.out.printf("%s=\"%s\"%n", key, kvp.get(key));
    }
    

    输出是

    key1="one two three"
    key2="four"
    key3="five six"
    key4="seven eight nine ten"
    

    【讨论】:

    • 当然,但我要的是正则表达式。无论如何+1,谢谢。 :-)
    【解决方案4】:

    如果空格不重复,类似的事情也是可能的:

    ([^\\s=]+)=([^=]+(?=\\s|$))
    

    否则你总是可以这样写:

    ([^\\s=]+)=([^=]+\\b(?=\\s|$))
    

    如果键名不太长,因为它们使用回溯,这些模式是一个很好的解决方案。

    你也可以这样写,最多回溯一步:

    ([^\\s=]+)=(\\S+(?>\\s+[^=\\s]+)*(?!=))
    

    【讨论】:

    • 我尝试了所有 3 种模式,但似乎都没有。也许他们需要稍微修改一下。无论如何+1,谢谢。
    • @PNS:这三个模式是写直接在你的Java代码中使用的,如果你想在在线正则表达式测试器(regex101.com或regexplanet)中测试它们,你需要替换双反斜杠, 带有简单的反斜杠。这三种模式有效。最后一个可能更有效。 (参见 regex101 中的调试器)
    猜你喜欢
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 2019-11-26
    相关资源
    最近更新 更多