匹配键值模式正则表达式

时间:2014-12-22 05:12:06

标签: java regex

我正在创建一个键值解析器,其中输入字符串采用key:"value",key2:"value"的形式。键可以包含字符a-zA-Z0-9,值可以包含除:,"和{{1}之外的任何字符需要以反斜杠为前缀。逗号用于分隔键值对,但在最后一对之后不需要。

到目前为止,我有\,它将匹配大多数键和值,但显然它不能处理多个对或者任何“控制”字符未转义。 ([a-zA-Z0-9]+):"(.*)"似乎匹配所有转义字符,但它不匹配任何“普通”字符。

有没有办法检查逗号分隔并匹配所有转义的“控制”字符以及正常字符?这是否更适合没有正则表达式的实现,还是需要按顺序排列多个模式?

一些例子:

输入:(?<=\\)[:,"\\]输出:joe:"bread",sam:"fish" joe -> bread

输入:sam -> fish输出:joe:"Look over there\, it's a shark!",sam:"I like fish." joe -> Look over there, it's a shark!

2 个答案:

答案 0 :(得分:2)

您可以使用以下正则表达式来获取键值对。

([a-zA-Z0-9]+):"(.*?)(?<!\\)"

OR

([a-zA-Z0-9]+):"(.*?)"(?=,[a-zA-Z0-9]+:"|$)

DEMO

Java正则表达式,

"([a-zA-Z0-9]+):\"(.*?)(?<!\\\\)\""

(?<!\\)"负面的后视断言双引号不会被反斜杠字符所取代。在java中,要匹配反斜杠字符,您需要将模式中的反斜杠转义三次,即\\\\

DEMO

String s = "joe:\"Look over there\\, it's a shark!\",sam:\"I like fish.\"";

Matcher m = Pattern.compile("([a-zA-Z0-9]+):\"(.*?)(?<!\\\\)\"").matcher(s);
    while(m.find())
    {
        System.out.println(m.group(1) + " --> " + m.group(2));
    }
}

输出:

joe --> Look over there\, it's a shark!
sam --> I like fish.

OR

String s = "joe:\"Look over there\\, i\\\"t's a shark!\",sam:\"I like fish.\"";

Matcher m = Pattern.compile("([a-zA-Z0-9]+):\"((?:\\\\\"|[^\"])*)\"").matcher(s);
    while(m.find())
    {
        System.out.println(m.group(1) + " --> " + m.group(2));
    }
}

输出:

joe --> Look over there\, i\"t's a shark!
sam --> I like fish.

答案 1 :(得分:1)

假设\后跟除行终止符之外的任何字符指定紧随其后的字符。

您可以使用以下正则表达式匹配键值对的所有实例:

"([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\""

如果您想允许空闲间距,请在\\s*之前和之后添加:

这就是正则表达式引擎所看到的:

([a-zA-Z0-9]+):"((?:[^\\"]|\\.)*+)"

量词*具有占有性*+,因为2个分支[^\\"]\\.是互斥的(两个字符串不能同时匹配) 。它还避免了Oracle StackOverflowError类的实现中的Pattern

在Matcher循环中使用上面的正则表达式:

Pattern keyValuePattern = Pattern.compile("([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\"");
Matcher matcher = keyValuePattern.matcher(inputString);

while (matcher.find()) {
    String key = matcher.group(1);

    // Process the escape sequences in the value string
    String value = matcher.group(2).replaceAll("\\\\(.)", "$1");

    // ...
}

一般情况下,根据转义序列的复杂程度(例如\n\uhhhh\xhh\0),您可能需要编写单独的函数解析他们。但是,根据上述假设,单线程就足够了。

请注意,此解决方案并不关心分隔符。它将跳过无效输入到最近的匹配。在下面的无效输入示例中,上面的解决方案将在开头跳过abc:",并愉快地将xyz:"text text" amd more:"pair"作为键值对匹配:

abc:"xyz:"text text", more:"pair"

如果不希望出现这种情况,则有一个解决方案,但必须首先隔离包含所有键值对的字符串,而不是与键没有任何关系的更大字符串的一部分 - 值对:

"(?:^|(?!^)\\G,)([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\""

自由空间版本:

"(?:^\s*|(?!^)\\G\s*,\s*)([a-zA-Z0-9]+)\s*:\s*\"((?:[^\\\\\"]|\\\\.)*+)\""