2016-07-29 66 views
1

我有此格式的自定義數據文件:遞歸收集串塊蟒蛇

{ 
    data = { 
     friends = { 
      max = 0 0, 
      min = 0 0, 
     }, 
     family = { 
      cars = { 
       van = "honda", 
       car = "ford", 
       bike = "trek", 
      }, 
      presets = { 
       location = "italy", 
       size = 10, 
       travelers = False, 
      }, 
      version = 1, 
     }, 
    }, 
} 

我想收集數據的塊,每個集合{同時保持hierarhcy}之間意義的字符串。這些數據不是典型的json格式,因此這不是一個可行的解決方案。

我的想法是創建一個像這樣

class Block: 
    def __init__(self, header, children): 
     self.header = header 
     self.children = children 

類對象在那裏我會再循環通過線數據線「莫名其妙」收集必要的數據,所以我的輸出結果想是這樣的.. 。

Block("data = {}", [ 
    Block("friends = {max = 0 0,\n min = 0 0,}", []), 
    Block("family = {version = 1}", [...]) 
]) 

總之我正在尋找關於如何幫助我可以序列化爲有用的數據,那麼我可以很容易地操縱這一點。所以我的方法是通過使用{}作爲分隔符來分解對象。 如果任何人有更好的方法來解決這個問題的建議,我會全力以赴。再次感謝你。

到目前爲止,我只是執行的代碼

class Block: 
    def __init__(self, content, children): 
     self.content = content 
     self.children = children 

def GetBlock(strArr=[]): 
    print len(strArr) 
# blocks = [] 
    blockStart = "{" 
    blockEnd = "}" 

with open(filepath, 'r') as file: 
    data = file.readlines() 
    blocks = GetBlock(strArr=data) 
+0

你到目前爲止有多遠?遞歸地實現這個應該很容易。 – filmor

+0

@filmor我已更新帖子以顯示我的代碼到目前爲止...我有點卡住,雖然不清楚如何繼續下去。 – JokerMartini

+0

這是什麼意思? 0 0,數組?如果那個不存在,你可以將=替換爲:並且ast.literal_eval會這樣做,除非你有=內部的字符串。 – YOU

回答

1

您可以創建一個to_block函數,它的線條從您的文件作爲一個迭代和遞歸那些創建了一個嵌套的字典中的基本片段。 (當然你也可以使用自定義Block類,但我實在不明白這樣做的好處。)

def to_block(lines): 
    block = {} 
    for line in lines: 
     if line.strip().endswith(("}", "},")): 
      break 
     key, value = map(str.strip, line.split(" = ")) 
     if value.endswith("{"): 
      value = to_block(lines) 
     block[key] = value 
    return block 

當調用它,你必須剝去第一線,雖然。另外,評估「葉」到例如數字或字符串作爲練習留給讀者。

>>> to_block(iter(data.splitlines()[1:])) 
{'data': {'family': {'version': '1,', 
        'cars': {'bike': '"trek",', 'car': '"ford",', 'van': '"honda",'}, 
        'presets': {'travelers': 'False,', 'size': '10,', 'location': '"italy",'}}, 
      'friends': {'max': '0 0,', 'min': '0 0,'}}} 

或從文件中讀取數據時:或者

with open("data.txt") as f: 
    next(f) # skip first line 
    res = to_block(f) 

,你可以做一些預處理該字符串轉換成JSON(-ish)的字符串,然後使用json.loads。但是,我不會一路走到這裏,而只是將值包裝到""(並在此之前將原始的"替換爲'),否則意外地將空格字符串轉換爲列表或類似字符的風險太大。您可以在創建JSON數據後對其進行排序。

>>> data = data.replace('"', "'") 
>>> data = re.sub(r'= (.+),$',  r'= "\1",', data, flags=re.M) 
>>> data = re.sub(r'^\s*(\w+) = ', r'"\1": ', data, flags=re.M) 
>>> data = re.sub(r',$\s*}',  r'}',  data, flags=re.M) 
>>> json.loads(data) 
{'data': {'family': {'version': '1', 
        'presets': {'size': '10', 'travelers': 'False', 'location': "'italy'"}, 
        'cars': {'bike': "'trek'", 'van': "'honda'", 'car': "'ford'"}}, 
      'friends': {'max': '0 0', 'min': '0 0'}}} 
+0

這是一個偉大的和聰明的解決方案,似乎正在爲我所需要的工作。很高興它或多或少地將它轉換爲json格式。現在更容易管理。 – JokerMartini

+0

你調用這個函數的代碼是什麼樣的? (文件路徑,'r')作爲文件: \t data = file.read() \t results = to_block(iter(data.splitlines()[1:-1]))' – JokerMartini

+0

@JokerMartini是的,像那樣。儘管如此,你不得不首先閱讀文件。猜猜你可以將它包裝在另一個函數中,以適當地處理第一行和最後一行。 –

1

你也可以用ast或json做正則表達式替換。

import re 

a = """{ 
    data = { 
     friends = { 
      max = 0 0, 
      min = 0 0, 
     }, 
     family = { 
      cars = { 
       van = "honda", 
       car = "ford", 
       bike = "trek", 
      }, 
      presets = { 
       location = "italy", 
       size = 10, 
       travelers = False, 
      }, 
      version = 1, 
     }, 
    }, 
}""" 

#with ast 
a = re.sub("(\w+)\s*=\s*", '"\\1":', a) 
a = re.sub(":\s*((?:\d+)(?: \d+)+)", lambda x:':[' + x.group(1).replace(" ", ",") + "]", a) 
import ast 
print ast.literal_eval(a) 
#{'data': {'friends': {'max': [0, 0], 'min': [0, 0]}, 'family': {'cars': {'car': 'ford', 'bike': 'trek', 'van': 'honda'}, 'presets': {'travelers': False, 'location': 'italy', 'size': 10}, 'version': 1}}} 

#with json 
import json 
a = re.sub(",(\s*\})", "\\1", a) 
a = a.replace(":True", ":true").replace(":False", ":false").replace(":None", ":null") 
print json.loads(a) 
#{u'data': {u'friends': {u'max': [0, 0], u'min': [0, 0]}, u'family': {u'cars': {u'car': u'ford', u'bike': u'trek', u'van': u'honda'}, u'presets': {u'travelers': False, u'location': u'italy', u'size': 10}, u'version': 1}}} 
+0

不錯,但如果有例如像「van =」honda「」crysler「這樣的字符串列表,並且可能偶然發現示例中未顯示的其他不合格項。 –

+0

@tobias_k,我沒有補充說,因爲OP似乎並不需要它,通常正則表達式解決方案是快速和骯髒的一次性方法。 – YOU