2013-02-18 228 views
2

我试图解析逗号分隔的列表,同时忽略大括号,括号或括号内定义的内部结构中的逗号。例如,这个字符串:正则表达式在逗号分割,但不包括花括号,括号和圆括号内的那些

'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, {}, [],()] 

到目前为止,我有以下......这是接近,但在嵌套结构断裂

任何帮助将不胜感激!

+3

你可以修改你的数据源来产生正确的JSON吗?然后它是微不足道的...... – 2013-02-18 18:29:41

+0

对于我的场景,分离,绑定和缓存单个绑定字符串将更有效,而不是将它们全部作为一组进行。 – bigmac 2013-02-18 18:36:57

+0

然后以便于分开的方式存储它们。例如,作为JSON数组的字符串(如果你讨厌一组对象)。 – 2013-02-18 18:39:02

回答

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 

这并不与“丑”字符串的工作(报价括号,转义引号,逃脱逃脱......)。这个解析器应该正确地解析所有有效输入,同时仍然相对简单:

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"仅仅是一个例子的修复需要一个更好(更COMLEX)语法,并accompanyingly更复杂的解析器


话说回来,是不是更好只使用JSON传输数据

选项1:一个真正的对象:{"text":"firstName", "css":{ ...
选项2(只有你真的希望如此):一串字符串:["text:firstName, css:{ ...

在这两种情况下,JSON.parse(input)是你的朋友。

相关问题