2014-05-05 211 views
5

我有一個相當難的問題,我只是無法修復.. 這個想法是循環瀏覽部分數據並找到任何縮進。 (總是空格) 每一行的縮進比前一個更大,例如4個空格,第一行應該是字典的關鍵字,並且應該附加下一個值。通過數據循環嵌套字典

如果還有另一個縮進,這意味着應該創建一個帶有鍵和值的新字典。這應該發生遞歸,直到通過數據。 爲了讓事情更容易理解我做了一個例子:

Chassis 1: 
    Servers: 
     Server 1/1: 
      Equipped Product Name: EEE UCS B200 M3 
      Equiped PID: e63-samp-33 
      Equipped VID: V01 
      Acknowledged Cores: 16 
      Acknowledged Adapters: 1 
    PSU 1: 
     Presence: Equipped 
     VID: V00 
     HW Revision: 0 

的想法是能夠得到在字典的形式返回數據的任何部分。 dictionary.get(「Chassis 1:」)應該返回所有數據,dictionary.get(「Servers」)應該返回比「Servers」行更深地縮進的所有內容。字典.get(「PSU 1:」)應該給出{「PSU 1:」:「Presence:Equipped」,「VID:100」,「HW Revision:0」}等等。 我已經繪製了一個小計劃來證明這一點,每種顏色是另一個字典。

當縮進再次變得較小時,例如從8到4個空格時,應將數據附加到數據較少縮進的字典中。

我已經把它在代碼試圖,但它不來接近我想要的任何地方..

for item in Array: 
    regexpatt = re.search(":$", item) 
    if regexpatt: 
     keyFound = True 
     break 

if not keyFound: 
    return Array 

#Verify if we still have lines with spaces 
spaceFound = False 
for item in Array: 
    if item != item.lstrip(): 
     spaceFound = True 
     break 

if not spaceFound: 
    return Array 

keyFound = False 
key="" 
counter = -1 
for item in Array: 
    counter += 1 
    valueTrim = item.lstrip() 
    valueL = len(item) 
    valueTrimL = len(valueTrim) 
    diff = (valueL - valueTrimL) 
    nextSame = False 
    if item in Array: 
     nextValue = Array[counter] 
     nextDiff = (len(nextValue) - len(nextValue.lstrip())) 
     if diff == nextDiff: 
      nextSame = True 


    if diff == 0 and valueTrim != "" and nextSame is True: 
     match = re.search(":$", item) 
     if match: 
      key = item 
      newArray[key] = [] 
      deptDetermine = True 
      keyFound = True 
    elif diff == 0 and valueTrim != "" and keyFound is False: 
     newArray["0"].append(item) 
    elif valueTrim != "": 
     if depthDetermine: 
      depth = diff 
      deptDetermine = False 
     #newValue = item[-valueL +depth] 
     item = item.lstrip().rstrip() 
     newArray[key].append(item) 

for item in newArray: 
    if item != "0": 
     newArray[key] = newArray[key] 

return newArray 

結果應該是這樣的,例如:

{ 
    "Chassis 1": { 
     "PSU 1": { 
      "HW Revision: 0", 
      "Presence: Equipped", 
      "VID: V00" 
     }, 
     "Servers": { 
      "Server 1/1": { 
       "Acknowledged Adapters: 1", 
       "Acknowledged Cores: 16", 
       "Equiped PID: e63-samp-33", 
       "Equipped Product Name: EEE UCS B200 M3", 
       "Equipped VID: V01" 
      } 
     } 
    } 
} 

我希望這解釋了足夠的概念

+0

那麼你的代碼是做什麼的,哪些做得不夠精確? – jonrsharpe

+0

您需要實現一個下推式自動機。 –

+0

jonrsharpe它製作了一個帶有鍵/列表的字典,但沒有正確的格式或順序,所以我選擇不包含'結果',因爲它包含相當多的缺陷.. @JoelCornett任何示例或答案?隨意張貼一些東西! – Yenthe

回答

4

這應該給你你想要的嵌套結構。

如果你想每個嵌套dictonary,也可以從根。取消對if .. is not root部分

def parse(data): 

    root = {} 
    currentDict = root 
    prevLevel = -1 
    parents = [] 
    for line in data: 
     if line.strip() == '': continue 
     level = len(line) - len(line.lstrip(" ")) 
     key, value = [val.strip() for val in line.split(':', 1)] 

     if level > prevLevel and not len(value): 
      currentDict[key] = {} 
      # if currentDict is not root: 
      #  root[key] = currentDict[key] 
      parents.append((currentDict, level)) 
      currentDict = currentDict[key] 
      prevLevel = level 
     elif level < prevLevel and not len(value): 
      parentDict, parentLevel = parents.pop() 
      while parentLevel != level: 
       if not parents: return root 
       parentDict, parentLevel = parents.pop() 
      parentDict[key] = {} 
      parents.append((parentDict, level)) 
      # if parentDict is not root: 
      #  root[key] = parentDict[key] 
      currentDict = parentDict[key] 
      prevLevel = level 
     else: 
      currentDict[key] = value 
    return root 




with open('data.txt', 'r') as f: 
    data = parse(f) 
    #for pretty print of nested dict 
    import json 
    print json.dumps(data,sort_keys=True, indent=4) 

輸出:

{ 
    "Chassis 1": { 
     "PSU 1": { 
      "HW Revision": "0", 
      "Presence": "Equipped", 
      "VID": "V00" 
     }, 
     "Servers": { 
      "Server 1/1": { 
       "Acknowledged Adapters": "1", 
       "Acknowledged Cores": "16", 
       "Equiped PID": "e63-samp-33", 
       "Equipped Product Name": "EEE UCS B200 M3", 
       "Equipped VID": "V01" 
      } 
     } 
    } 
} 
+2

偉大的解決方案!如果我可以挑選,我不需要使用'str.count'來衡量'level',只需使用'level = len(line) - len(line.lstrip(「」))''。如果在鍵或值中存在':',則該代碼也會中斷,但這並不奇怪(大多數解析器要求分隔符不在任何字段中),因此它可能更多地是OP的註釋。 –

+0

我相信亞當所指的也正是它爲什麼會崩潰在我身上? 我得到以下錯誤: 「key,value = [val.strip()for line.split(':')] ValueError:需要多個值才能解包」 但是,如果這樣做的話可能是我需要的!任何線索爲什麼我得到這個錯誤? – Yenthe

+0

@AdamSmith謝謝,我提出了你的建議編輯。它應該稍微更有效率。我還添加了'line.split(':',1)',所以如果存在多個':',它不會中斷(但結果可能不合意)。 – M4rtini

4

這些數據格式確實看起來像YAML。萬一有人絆倒這是細帶庫解決方案:

import yaml 
import pprint 

s = """ 
Chassis 1: 
    Servers: 
     Server 1/1: 
      Equipped Product Name: EEE UCS B200 M3 
      Equiped PID: e63-samp-33 
      Equipped VID: V01 
      Acknowledged Cores: 16 
      Acknowledged Adapters: 1 
    PSU 1: 
     Presence: Equipped 
     VID: V00 
     HW Revision: 0 
""" 

d = yaml.load(s) 
pprint.pprint(d) 

輸出是:

{'Chassis 1': {'PSU 1': {'HW Revision': 0, 
         'Presence': 'Equipped', 
         'VID': 'V00'}, 
       'Servers': {'Server 1/1': {'Acknowledged Adapters': 1, 
              'Acknowledged Cores': 16, 
              'Equiped PID': 'e63-samp-33', 
              'Equipped Product Name': 'EEE UCS B200 M3', 
              'Equipped VID': 'V01'}}}} 

參考:

+0

可悲的是我不能安裝或使用yaml模塊,所以我不得不請求。這將成爲我的第二次備份,因爲這看起來很不錯而且簡單。 – Yenthe

+0

@Yenthe我無法想象有什麼要求可以阻止你使用這個庫。除了安裝它之外,您可以將源代碼下載到您的代碼庫(並將該程序包添加到您的PYTHONPATH中)。 – moooeeeep

+0

@mooeeeep可悲的是我在一個非常大的,受限制的公司。不幸的是,我必須要求最大的管理員許可。至少需要一天,如果它獲得批准.. – Yenthe