我正在尝试解析以逗号分隔的列表,同时省略属于由大括号,括号或括号定义的内部结构的逗号。例如,这个字符串:
'text:firstName,css:{left:x,top:y},values:["a","b"],visible:(true,false),broken:["str", 1, {}, [],()]'
应分为:
text:firstName
css:{left:x,top:y}
values:["a","b"]
visible:(true,false)
broken:["str", 1, {}, [],()]
到目前为止,我已经得到了以下内容......这种情况很接近,但在嵌套结构上会中断:
[^,\[\]{}]+(({|\[)[^\[\]{}]*(}|\]))?
非常感谢任何帮助!
答案 0 :(得分:1)
除非您愿意更改数据格式,或者您可以在接收后找到一种简单的方法将其转换为正确的JSON,但最好的办法是手动解析。
最简单的匹配器(假设“漂亮”值):
On ([{ - increment parens
On )]} - decrement parens or emit error if parens is zero
On , - emit and reset the buffer if parens is zero (finish a match)
If not , - push into the output buffer
这不适用于“丑陋”的字符串(引用的parens,转义引号,转义转义......)。这个解析器应该正确地解析所有有效的输入,同时仍然相对简单:
On ([{ - increment parens if the state is "start". Push to buffer.
On )]} - decrement parens if the state is "start" and parens is positive.
Emit an error if parens is zero. Push to buffer.
On , - emit and reset the buffer if parens is zero and the state is "start"
(finish a match). Push to buffer.
On \ - Push to buffer, and push and read the next symbol as well.
On ' - If the state is "start", change the state to "squote", and vice versa.
Push to buffer.
On " - If the state is "start", change the state to "dquote", and vice versa.
Push to buffer.
On EOF - Emit error if parens is not zero or the state is not "start".
以下是Javascript中实现的草图:
function splitLiteralBodyByCommas(input){
var out = [];
var iLen = input.length;
var parens = 0;
var state = "";
var buffer = ""; //using string for simplicity, but an array might be faster
for(var i=0; i<iLen; i++){
if(input[i] == ',' && !parens && !state){
out.push(buffer);
buffer = "";
}else{
buffer += input[i];
}
switch(input[i]){
case '(':
case '[':
case '{':
if(!state) parens++;
break;
case ')':
case ']':
case '}':
if(!state) if(!parens--)
throw new SyntaxError("closing paren, but no opening");
break;
case '"':
if(!state) state = '"';
else if(state === '"') state = '';
break;
case "'":
if(!state) state = "'";
else if(state === "'") state = '';
break;
case '\\':
buffer += input[++i];
break;
}//end of switch-input
}//end of for-input
if(state || parens)
throw new SyntaxError("unfinished input");
out.push(buffer);
return out;
}
这个解析器仍然存在缺陷:
它允许用括号等关闭parens。要解决此问题,请使parens
成为一堆符号;如果开始和结束符号不匹配,则引发异常。
它允许格式错误的unicode转义字符串。解析器接受\utest
。
它允许转义顶级逗号。这可能不是错误:\,,\,
是一个有效的字符串,包含两个由未转义的字符分隔的顶级转义逗号。
尾随反斜杠会产生意外输出。同样,这将通过读取我们正在逃避的数据来解决。更简单的修复方法是buffer += input[++i] || ''
(附加一个空字符串而不是undefined
,但这会导致无效输入。
它允许各种其他无效输入:[""'']{'\\'}"a"
只是一个例子。修复需要更好(更复杂)的语法,并伴随着更复杂的解析器。
话虽如此,使用JSON传输数据不是更好吗?
选项1:真实对象:{"text":"firstName", "css":{
...
选项2(仅当你真的希望如此)时:字符串数组:["text:firstName, css:{
...
在这两种情况下,JSON.parse(input)
都是你的朋友。
答案 1 :(得分:0)
使用递归匹配:
(?>[^(){}[\], ]+:)?(?>(?>\([^()]*(?R)?[^()]*\))|(?>\[[^[\]]*(?R)?[^[\]]*\])|(?>{[^{}]*(?R)?[^{}]*})|(?>[^(){}[\], ]+))
第一部分匹配并包括冒号:
(?>[^(){}[\], ]+:)?
其余部分包含平衡 ()
、[]
、{}
以及除逗号或空格以外的任何其他选项:
(?>(?>\([^()]*(?R)?[^()]*\))|
(?>\[[^[\]]*(?R)?[^[\]]*\])|
(?>{[^{}]*(?R)?[^{}]*})|
(?>[^(){}[\], ]+))