我正在创建一个键值解析器,其中输入字符串采用key:"value",key2:"value"
的形式。键可以包含字符a-z
,A-Z
和0-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!
答案 0 :(得分:2)
您可以使用以下正则表达式来获取键值对。
([a-zA-Z0-9]+):"(.*?)(?<!\\)"
OR
([a-zA-Z0-9]+):"(.*?)"(?=,[a-zA-Z0-9]+:"|$)
Java正则表达式,
"([a-zA-Z0-9]+):\"(.*?)(?<!\\\\)\""
(?<!\\)"
负面的后视断言双引号不会被反斜杠字符所取代。在java中,要匹配反斜杠字符,您需要将模式中的反斜杠转义三次,即\\\\
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*\"((?:[^\\\\\"]|\\\\.)*+)\""