2015-10-07 10 views
5

Ho un file che contiene righe in questo tipo di formato.divide una riga in un dizionario con più livelli di coppie di valori chiave

Example 1: 
nextline = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4 };" 

Example 2: 
nextline = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4; Player2 = 6; Player3 = 4 };" 

Prima ho diviso la riga con ":" che mi fornisce una lista con 2 voci. Mi piacerebbe dividere questa linea in un dizionario con una chiave e un valore, ma dove la chiave dello spartito ha più sottochiavi con un valore.

Hole 1 
Par 4 
Index 2 
Distance 459 
Score 
    Player1 4 
    Player2 6 
    Player3 4 

Così sto usando qualcosa di simile ...

split_line_by_semicolon = nextline.split(":") 
dictionary_of_line = dict((k.strip(), v.strip()) for k,v in (item.split('=')  
    for item in split_line_by_semicolon.split(';'))) 
     for keys,values in dictionary_of_line.items(): 
      print("{0} {1}".format(keys,values)) 

Tuttavia ottengo un errore sull'elemento score della linea:

ValueError: too many values to unpack (expected 2) 

posso regolare la spaccatura su '=' a questo, quindi si ferma dopo il primo '='

dictionary_of_line = dict((k.strip(), v.strip()) for k,v in (item.split('=',1)  
    for item in split_line_by_semicolon.split(';'))) 
     for keys,values in dictionary_of_line.items(): 
      print("{0} {1}".format(keys,values)) 

Tuttavia, perdo i valori secondari all'interno delle parentesi graffe. Qualcuno sa come posso ottenere questo dizionario multistrato?

+0

'split_line_by_semicolon.split (';')' non sembra giusto per me. 'split_line_by_semicolon' è una lista, e gli elenchi non hanno un metodo' split'. Sei sicuro che questo sia esattamente il codice che stai utilizzando? – Kevin

+0

corretto. Ci sono altre cose nella riga che analizzo per arrivare alla carne. Quindi è in realtà split_line_by_semicolon [3] – John

risposta

2

Un modo più semplice per farlo (ma non so se è accettabile nella vostra situazione) sarebbe:

import re 

nextline = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4; Player2 = 6; Player3 = 4 };" 

# compiles the regular expression to get the info you want 
my_regex = re.compile(r'\w+ \= \w+') 

# builds the structure of the dict you expect to get 
final_dict = {'Hole':0, 'Par':0, 'Index':0, 'Distance':0, 'Score':{}} 

# uses the compiled regular expression to filter out the info you want from the string 
filtered_items = my_regex.findall(nextline) 

for item in filtered_items: 
    # for each filtered item (string in the form key = value) 
    # splits out the 'key' and handles it to fill your final dictionary 
    key = item.split(' = ')[0] 
    if key.startswith('Player'): 
     final_dict['Score'][key] = int(item.split(' = ')[1]) 
    else: 
     final_dict[key] = int(item.split(' = ')[1]) 
+1

Grazie. Mi piace questo. Si inserisce perfettamente. – John

0
lines = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4 };", "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4; Player2 = 6; Player3 = 4 };" 

def lines_to_dict(nextline): 
    import json 
    # cut up to Hole 
    nextline = nextline[nextline.index("Hole"):] 
    # convert to dict format 
    string_ = re.sub(r'\s+=',':',nextline) 
    string_ = re.sub(r';',',',string_) 
    # json likes double quotes 
    string_ = re.sub(r'(\b\w+)',r'"\1"',string_) 
    string_ = re.sub(r',$',r'',string_) 
    # make dict for Hole 
    mo = re.search(r'(\"Hole.+?),\W+Score.*',string_) 
    if mo: 
     d_hole = json.loads("{" + mo.groups()[0] + "}") 
    # make dict for Score 
    mo = re.search(r'(\"Score.*)',string_) 
    if mo: 
     d_score = json.loads("{" + mo.groups()[0] + "}") 
    # combine dicts 
    d_hole.update(d_score) 
    return d_hole 

for d in lines: 
pprint.pprint(lines_to_dict(d)) 

{'Distance': '459', 
'Hole': '1', 
'Index': '2', 
'Par': '4', 
'Score': {'Player1': '4'}} 

{'Distance': '459', 
'Hole': '1', 
'Index': '2', 
'Par': '4', 
'Score': {'Player1': '4', 'Player2': '6', 'Player3': '4'}} 
1

avrei usato le espressioni regolari nello stesso modo in cui ha fatto maccinza (mi piace la sua risposta), con una minore differenza - un data con il dizionario interno in esso può essere elaborato in modo ricorsivo:

#example strings: 
nextline1 = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4 };" 
nextline2 = "DD:MM:YYYY INFO - 'WeeklyMedal: Hole = 1; Par = 4; Index = 2; Distance = 459; Score = { Player1 = 4; Player2 = 6; Player3 = 4 };" 

import re 
lineRegexp = re.compile(r'.+\'WeeklyMedal:(.+)\'?') #this regexp returns WeeklyMedal record. 
weeklyMedalRegexp = re.compile(r'(\w+) = (\{.+\}|\w+)') #this regexp parses WeeklyMedal 

#helper recursive function to process WeeklyMedal record. returns dictionary 
parseWeeklyMedal = lambda r, info: { k: (int(v) if v.isdigit() else parseWeeklyMedal(r, v)) for (k, v) in r.findall(info)} 
parsedLines = [] 
for line in [nextline1, nextline2]: 
    info = lineRegexp.search(line) 
    if info: 
     #process WeeklyMedal record 
     parsedLines.append(parseWeeklyMedal(weeklyMedalRegexp, info.group(0))) 
     #or do something with parsed dictionary in place 

# do something here with entire result, print for example 
print(parsedLines) 
Problemi correlati