2017-09-05 65 views
0

我有一個很長的字符串裏面很多JSONs檢索所有JSONs,它看起來像:正則表達式的表達式從一個長的字符串

{"a":"b"}{"c":"d"}{"e":"f"}... 

我準備的正則表達式表達式從那種字符串的提取所有JSONs:

\{(?:[^{}]|(?R))*\} 

它工作的很好,但它有一個問題。如果當它需要檢索這樣一個字符串失敗:

{"a":"b"}{"c":"d"}{"e":"f}"}... 

它假設,認爲「}」簽署「F」字母結束第三JSON後,但如果當然不。你有沒有人知道我該如何解決這個REGEX?

代碼示例: https://regex101.com/r/L9UUzj/1

謝謝!

+0

你只需要比更精確'[^ {}]'和分別描述部件之間引號包圍。 –

回答

2

[^{}]不會在引號引起賬戶部分採取,而是可以將其替換爲:[^"{}]|"[^"]*"

你可以用這種模式做到這一點:

{[^"{}]*+(?:"[^"]*+"[^"{}]*+|(?R)[^"{}]*+)*+} 

demo

另外,如果您想要處理引用部分中的轉義引號(帶反斜槓):

{[^"{}]*+(?:"[^"\\]*+(?s:\\.[^"\\]*)*+"[^"{}]*+|(?R)[^"{}]*+)*+} 

demo

這兩種模式使用展開的設計,是更有效的。簡而言之,您不需要編寫(A|B)*,而是編寫A*(BA*)*,這需要更少的步驟。

佔有量詞*+是爲了防止當大括號在字符串中某個位置不平衡時防止大量回溯。這種方式在這個位置會很快失敗。

顯然,這兩種模式並沒有完全描述json語法。隨意使用命名組和(?(DEFINE)...)功能來做到這一點,這遠非不可能(*)。但是您也可以使用第二種模式來提取json子字符串,然後使用您選擇的json解析器來檢查它們。


(*)這樣的事情:

~ 
\g<object> 

(?(DEFINE) 
    (?<string> " [^"\\]*+ (?s: \\. [^"\\]*+)*+ ") 
    (?<table> \[ (?: \s* \g<value> (?: \s* , \s* \g<value>)*+)? \s* ]) 
    (?<object> { 
     (?: \s* \g<key> \s* : \s* \g<value> 
      (?: \s* , \s* \g<key> \s* : \s* \g<value>)*+ 
     )? \s* } 
    ) 
    (?<boolean> [Tt]rue | [Ff]alse) 
    (?<number> (?: [0-9]+ (?: \. [0-9]*)? | \.[0-9]+) 
       (?: [Ee] -? [0-9]+)?) 

    (?<key> \g<string> (?<= [^"]" | \\"")) 
    (?<value> \g<table> | \g<object> | \g<string> 
      | \g<number> | \g<boolean> | null) 
) 
~x 
+0

你太棒了。謝謝! – pronngo

+1

呵呵 - 我一直認爲「如果我處理反斜槓的引號,我還需要處理反斜槓的反斜槓,等等無限 - 感覺就像一個無盡的拉比盲人」 - 並完全避免了這個話題。但是你是對的,我只需要在反斜槓之後始終接受第一個字符,不管它是什麼。好極了!我學到了一件事! :D –

+1

@DewiMorgan:做得好,很少有人注意到並繼續寫下諸如'(?<!\\)(?:\\\\)* \\「'的東西。 –