2012-06-19 15 views
35

Inspirado por una pregunta ahora eliminada; dada una expresión regular con grupos con nombre, ¿hay un método como findall que devuelve una lista de dict con los grupos de captura nombrados en lugar de una lista de tuple?re.findall que devuelve un dict de grupos de captura nombrados?

dado:

>>> 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')] 

lugar, debe dar:

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

Respuesta

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

Esta es una solución mucho mejor que mi versión, que se centró en el uso de 'findall' desde el primer momento. – beerbajay

+0

Esto es muy útil, ¡gracias! – mVChr

1

No hay método integrado para hacer esto, pero el resultado esperado se puede lograr mediante el uso de listas por comprensión.

[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 formato amigable:

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

Construimos una lista usando una lista por comprensión, iterar sobre el resultado de findall que es o bien una lista de cadenas o una lista de tuplas (0 ó 1 captura los grupos dan como resultado una lista de str).

Para cada elemento en el resultado se construye un dict de otra lista de comprensión que se genera desde el campo del patrón compilado groupindex, que se parece:

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

se construye una lista para cada elemento de la groupindex y si el artículo de findall era una tupla, se usa el número de grupo de groupindex para encontrar el artículo correcto, de lo contrario, el elemento se asigna al grupo con nombre (solo existente).

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

Finalmente, un dict se construye a partir de la lista de listas de cadenas.

Tenga en cuenta que groupindex contiene solo grupos con nombre, por lo que los grupos de captura sin nombre se omitirán del resultado dict.

Y el resultado:

[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

que podría cambiar 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

Si está utilizando partido:

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

documentation here

Cuestiones relacionadas