2013-02-14 10 views
5

Voglio chiedere il vostro aiuto.Python: regex per catturare i dati

Ho un grande pezzo di dati, che assomiglia a questo:

 a 
    b : c 901 
    d : e sda 
v 
    w : x ads 
    any 
    abc : def 12132 
    ghi : jkl dasf 
    mno : pqr fas 
    stu : vwx utu 

Descrizione: file inizia con una riga contenente singola parola (che può iniziare con spazi e spazi bianchi può essere anche dopo la parola), quindi segue la linea di attributi separati da due punti (può avere anche spazi bianchi), quindi una riga di attributi o una riga con una singola parola. Non riesco a creare la regex diritto di prenderlo nella forma:

{ 
    "a": [["b": "c 901"], ["d", "e sda"]], 
    "v": [["w", "x ads"]], 
    "any": ["abc", "def 12132"], ["ghi", "jkl dasf"], 
    # etc. 
} 

Ecco che cosa ho provato:

regex = str() 
regex += "^(?:(?:\\s*)(.*?)(?:\\s*))$", 
regex += "(?:(?:^(?:\\s*)(.*?)(?:\\s*):(?:\\s*)(.*?)(?:\\s*))$)*$" 
pattern = re.compile(regex, re.S | re.M) 

Tuttavia, non trova quello che mi serve. Potresti aiutarmi? So che posso elaborare il file senza regex, usando l'iteratore linea per riga e controllando il simbolo ":", ma il file è troppo grande per elaborarlo in questo modo (se sai come elaborarlo velocemente senza regex, anche questo sarà risposta giusta, ma prima quello che viene in mente è troppo lento).

Grazie in anticipo!

P.S. Nella forma canonica di file ha un aspetto simile a questo:

a 
    b : c 901 
    d : e sda 

Ogni sezione inizia con una sola parola, quindi seguire la linea attributi (dopo due spazi bianchi), ci attributi sono separati con (":"), quindi Agane attributi linea o linea con una singola parola. Altri spazi bianchi sono proibiti. Probabilmente sarà più facile.

+0

+1 Super chiarezza; Domanda ben incorniciata. – Yavar

risposta

3

Le espressioni regolari sono davvero necessarie qui? Prova questo pseudocodice:

result = {} 

last = None 
for _line in data: 
    line = _line.strip().split(":") 
    if len(line) == 1: 
     last = line[ 0 ] 
     if last not in result: 
      result[ last ] = [] 
    elif len(line) == 2: 
     obj = [ line[ 0 ].strip(), line[ 1 ].strip() ] 
     result[ last ].append(obj) 

Spero di aver compreso correttamente la struttura dei dati.

+2

Questo è l'approccio corretto, nessuna regex necessaria, ho avuto una risposta qui ho eliminato perché non è inutile, questa è la soluzione che ti serve. (potrebbe essere necessario un piccolo ritocco, ma è quello che vuoi) +1 –

0

È possibile utilizzare questa espressione regolare ..

(?:[\n\r]+|^)\s*(\w+)\s*[\n\r]+(\s*\w+\s*:\s*.*?)(?=[\n\r]+\s*\w+\s*[\n\r]+|$) 

È necessario partita quanto sopra regex con singleline o dotall opzione

Gruppo1 e Gruppo2 corrisponde a ciò che si desidera che ogni volta che si abbinare

check out here .. use dot all option

0
# a more golf - like solution 
from itertools import groupby 

groups = groupby(map(lambda s: map(str.strip,s.split(':')), data), len) 
dict((next(i[1])[0], list(next(groups)[1])) for i in groups) 

out:

{'a': [['b', 'c 901'], ['d', 'e sda']], 
'any': [['abc', 'def 12132'], 
    ['ghi', 'jkl dasf'], 
    ['mno', 'pqr fas'], 
    ['stu', 'vwx utu']], 
'v': [['w', 'x ads']]}