2012-04-07 15 views
1

我想解析類似JSON的字符串。它們與正常JSON的唯一區別在於數組中存在連續的逗號。當有兩個這樣的逗號時,它隱含地意味着應該在中間插入null。例如:Python:解析類似JSON的Javascript數據結構(w /連續逗號)

 JSON-like: ["foo",,,"bar",[1,,3,4]] 
     Javascript: ["foo",null,null,"bar",[1,null,3,4]] 
Decoded (Python): ["foo", None, None, "bar", [1, None, 3, 4]] 

原生json.JSONDecoder類不允許我更改數組解析的行爲。我只能修改解析器的對象(字典),整數,浮點數,字符串(通過給予kwargs函數JSONDecoder(),請參閱the doc)。

那麼,這是否意味着我必須從頭開始編寫JSON解析器? Python代碼json是可用的,但它是相當混亂。我寧願使用它的內部而不是重複它的代碼!

+0

檢查我的問題,看看我是如何解決它,並按照更快的方式:http://stackoverflow.com/questions/17901156/fastest-way-to-convert-javascript-object-array- to-python-dict-list?noredirect = 1#comment26148131_17901156 – 2013-07-28 11:53:36

回答

3

小&簡單的解決方法可以試試:

  1. 轉換類JSON數據字符串。
  2. 將「,,」替換爲「,null」。
  3. 將其轉換爲任何您的代表。
  4. 讓JSONDecoder(), 做繁重的工作。

    1. & 3.可以,如果你已經使用字符串處理被省略。

(如果轉換爲字符串是不現實的,更新此信息您的問題!)

+0

謝謝。我已經嘗試過這樣做了。我已經使用了一個簡單的re.sub,但有時候,一些',null ,,'仍然存在。這種解決方法有點太髒! – zopieux 2012-04-07 19:14:06

+0

不幸的是,它並不像這樣簡單,因爲當你用'','null'替換'''''時,你用逗號加上'',所以你從'''''''''''''''空,''仍然失敗。 – 2012-04-07 19:22:40

+0

@Lattyware但是如果你使用了一個倒序,如[我的答案](http://stackoverflow.com/a/10057585/344821),一切都很好。無論如何,它都適用於您的示例。 :) – Dougal 2012-04-07 19:23:30

5

既然你試圖解析究竟是不是JSON 本身,而是與JSON非常相似的不同語言,您可能需要您自己的解析器。

幸運的是,這並不像聽起來那麼難。您可以使用Python解析器生成器,如pyparsing。 JSON可以用一個相當簡單的上下文無關語法(我找到了一個here)完全指定,所以你應該能夠修改它以適應你的需要。

+0

也許它的矯枉過正,但其他人可能需要它!所以,+1我! – 2012-04-07 19:17:38

+1

+1。請注意,雖然我的答案確實給了你一些應該工作的東西(據我所能想到的),這是一個更好的解決方案。這可能是更多的工作,但它會更有彈性。如果你做的東西很小,那麼盡一切辦法,用我的黑客,但如果你做的更重要的事情,做好。 – 2012-04-07 19:18:24

+1

@Lattyware這絕對是真的。例如,如果字符串對象中存在逗號逗號,我們的方法就會搞亂。 – Dougal 2012-04-07 19:26:04

1

這樣做是一種駭人的方式,但一種解決方案是簡單地對JSON-ish數據進行一些字符串修改,以便在解析它之前將其排成一行。

import re 
import json 

not_quite_json = '["foo",,,"bar",[1,,3,4]]' 
not_json = True 
while not_json: 
    not_quite_json, not_json = re.subn(r',\s*,', ', null, ', not_quite_json) 

這給我們留下了:

'["foo", null, null, "bar",[1, null, 3,4]]' 

然後,我們可以這樣做:

json.loads(not_quite_json) 

給予我們:

['foo', None, None, 'bar', [1, None, 3, 4]] 

注意,它不是一個取代一樣簡單,因爲替換也插入了可以n的逗號取代。鑑於此,您必須循環,直到不能進行更換。在這裏,我使用了一個簡單的正則表達式來完成這項工作。

2

您可以通過使用一個回顧後表達做了逗號更換Lattyware's/przemo_li's答案在一次通過,即「替代由只是一個逗號之前的所有逗號」:

>>> s = '["foo",,,"bar",[1,,3,4]]' 

>>> re.sub(r'(?<=,)\s*,', ' null,', s) 
'["foo", null, null,"bar",[1, null,3,4]]' 

注意,這將工作例如,對於可以假定字符串中沒有連續逗號的小事情。一般來說,正則表達式不足以解決這個問題,使用真正解析器的Taymon's approach是唯一完全正確的解決方案。

+0

我知道必須有一種方法可以完全使用正則表達式,但是,唉,它超出了我的想象。 +1,這是一個更好的解決方案。 – 2012-04-07 19:23:48

+0

然而,你的代碼需要一個修復 - ''''''''''''''''''''''' ,),','null,',s)''。 – 2012-04-07 19:25:13

+0

@Lattyware當然 - 複製粘貼失敗。 – Dougal 2012-04-07 19:26:36

1

我看了一下Taymon的推薦,pyparsing,並且我成功地破解了提供的示例here以滿足我的需求。 它可以很好地模擬Javascript eval()失敗一種情況:尾隨逗號。應該有一個可選的尾隨逗號 - 見下面的測試 - 但我找不到任何適當的方式來實現這一點。

from pyparsing import * 

TRUE = Keyword("true").setParseAction(replaceWith(True)) 
FALSE = Keyword("false").setParseAction(replaceWith(False)) 
NULL = Keyword("null").setParseAction(replaceWith(None)) 

jsonString = dblQuotedString.setParseAction(removeQuotes) 
jsonNumber = Combine(Optional('-') + ('0' | Word('123456789', nums)) + 
        Optional('.' + Word(nums)) + 
        Optional(Word('eE', exact=1) + Word(nums + '+-', nums))) 

jsonObject = Forward() 
jsonValue = Forward() 
# black magic begins 
commaToNull = Word(',,', exact=1).setParseAction(replaceWith(None)) 
jsonElements = ZeroOrMore(commaToNull) + Optional(jsonValue) + ZeroOrMore((Suppress(',') + jsonValue) | commaToNull) 
# black magic ends 
jsonArray = Group(Suppress('[') + Optional(jsonElements) + Suppress(']')) 
jsonValue << (jsonString | jsonNumber | Group(jsonObject) | jsonArray | TRUE | FALSE | NULL) 
memberDef = Group(jsonString + Suppress(':') + jsonValue) 
jsonMembers = delimitedList(memberDef) 
jsonObject << Dict(Suppress('{') + Optional(jsonMembers) + Suppress('}')) 

jsonComment = cppStyleComment 
jsonObject.ignore(jsonComment) 

def convertNumbers(s, l, toks): 
    n = toks[0] 
    try: 
     return int(n) 
    except ValueError: 
     return float(n) 

jsonNumber.setParseAction(convertNumbers) 

def test(): 
    tests = (
     '[1,2]',  # ok 
     '[,]',   # ok 
     '[,,]',  # ok 
     '[ , , , ]', # ok 
     '[,1]',  # ok 
     '[,,1]',  # ok 
     '[1,,2]',  # ok 
     '[1,]',  # failure, I got [1, None], I should have [1] 
     '[1,,]',  # failure, I got [1, None, None], I should have [1, None] 
    ) 
    for test in tests: 
     results = jsonArray.parseString(test) 
     print(results.asList()) 
+0

而不是雙逗號字符串的黑魔法,你可以反而只是使空字符串在列表中的有效元素?這對我來說似乎比較乾淨,並且會在列表的末尾正常工作。 – Taymon 2012-04-07 22:35:18

+0

等一下,我的道歉,我誤解了這個問題。所以你想從每個有一個列表的末尾切掉一個尾隨隱含的'null'? – Taymon 2012-04-07 22:46:25

+0

我認爲你的選擇是做到這一點(解析字符串後,如果有的話,從列表中刪除一個尾部'null';你還必須確定它是隱式的而不是文字的),或明確允許尾部逗號在列表末尾,然後使用優先級來防止含糊不清。 – Taymon 2012-04-08 01:23:54