2013-02-18 282 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)是你的朋友。

相關問題