2012-06-19 11 views
35

Ispirato da una domanda cancellata; data una regex con gruppi denominati, esiste un metodo come findall che restituisce un elenco di dict con i gruppi di acquisizione denominati invece di un elenco di tuple?re.findall che restituisce un gruppo di gruppi di acquisizione denominati?

Dato:

>>> import re 
>>> text = "bob sue jon richard harry" 
>>> pat = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)') 
>>> pat.findall(text) 
[('bob', 'sue'), ('jon', 'richard')] 

dovrebbe invece dare:

[{'name': 'bob', 'name2': 'sue'}, {'name': 'jon', 'name2': 'richard'}] 

risposta

71
>>> import re 
>>> s = "bob sue jon richard harry" 
>>> r = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)') 
>>> [m.groupdict() for m in r.finditer(s)] 
[{'name2': 'sue', 'name': 'bob'}, {'name2': 'richard', 'name': 'jon'}] 
+0

Questa è una soluzione molto migliore della mia versione, che si è concentrata sull'uso di findall fin dall'inizio. – beerbajay

+0

Questo è molto utile, grazie! – mVChr

1

Non c'è alcun metodo incorporato per fare questo, ma il risultato atteso può essere raggiunto utilizzando list comprehensions.

[dict([[k, i if isinstance(i, str) else i[v-1]] for k,v in pat.groupindex.items()]) for i in pat.findall(text)] 

Con la formattazione amichevole:

>>> [ 
...  dict([ 
...   [k, i if isinstance(i, str) else i[v-1]] 
...   for k,v in pat.groupindex.items() 
...  ]) 
...  for i in pat.findall(text) 
... ] 

Costruiamo un elenco utilizzando una lista di comprensione, iterare il risultato da findall che è o una lista di stringhe o di una lista di tuple (0 o 1 cattura i gruppi generano un elenco di str).

Per ogni elemento nel risultato costruiamo un dict da un'altra comprensione lista che viene generato dal groupindex campo del modello compilato, che si presenta come:

>>> pat.groupindex 
{'name2': 2, 'name': 1} 

Un elenco è costruito per ogni elemento della groupindex e se l'articolo da findall era una tupla, il numero di gruppo da groupindex viene utilizzato per trovare l'elemento corretto, altrimenti l'elemento viene assegnato al gruppo denominato (solo esistente).

[k, i if isinstance(i, str) else i[v-1]] 

Infine, un dict viene creato dall'elenco di elenchi di stringhe.

Si noti che groupindex contiene solo gruppi con nome, quindi i gruppi di acquisizione senza nome verranno omessi dal risultante dict.

E il risultato:

[dict([[k, i if isinstance(i, str) else i[v-1]] for k,v in pat.groupindex.items()]) for i in pat.findall(text)] 
[{'name2': 'sue', 'name': 'bob'}, {'name2': 'richard', 'name': 'jon'}] 
9

si poteva passare a finditer

>>> import re 
>>> text = "bob sue jon richard harry" 
>>> pat = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)') 
>>> for m in pat.finditer(text): 
...  print m.groupdict() 
... 
{'name2': 'sue', 'name': 'bob'} 
{'name2': 'richard', 'name': 'jon'} 
3

Se si utilizza partita:

r = re.match('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)', text) 
r.groupdict() 

documentation here

Problemi correlati