Posible recuperar un conjunto desordenado arbitraria de grupos con nombre de un solo golpe con el módulo de regreso de Python?

StackOverflow https://stackoverflow.com/questions/2187931

  •  25-09-2019
  •  | 
  •  

Pregunta

Esto es súper práctico para algunos problemas:

>>> re.search('(?P<b>.b.).*(?P<i>.i.)', 'abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

Pero lo que si no sé qué orden puede esperar antes de tiempo?

[Actualización]

Por ejemplo, decir que tengo una variable de entrada que contiene un poco de orden desconocido de personajes y da la casualidad de que la 'b' que viene después 'i'. Quiero seguir siendo capaz de hacer referencia a los grupos de '.b.' y yo.' sin tener que pedir mi expresión regular de acuerdo a su orden en la entrada var. Por lo tanto, me gustaría poder hacer algo como esto, pero no sé si es posible:

>>> re.search('(?P<b>.b.)|(?P<i>.i.)', unknown_order_alphabet_str).groupdict()
{'i': 'hij', 'b': 'abc'}

[actualización final]

he buscado alrededor y devanaba los sesos un montón, pero no puede generar ninguna pista buenas. Adivinando no existiría esta funcionalidad, porque probablemente el único camino para volver a hacer esto es para escanear toda la cadena de una vez para cada grupo (que por supuesto que podía hacer en un bucle en su lugar) pero pensé que vería lo que el cerebro stackoverflow tenía que decir al respecto.

Gracias por su ayuda, España Josh

¿Fue útil?

Solución

Usar una barra vertical ( "o") en el patrón RE, y finditer para conseguir todos los objetos de los partidos de interés: cada uno tendrá un groupdict con None como el valor para los grupos que no participan en ese partido, y se puede "merge "los dicts como prefiera.

Por ejemplo:

import re

def mergedgroupdict(pattern, thestring):
  there = re.compile(pattern)
  result = {}
  for mo in there.finditer(thestring):
    d = mo.groupdict()
    for k in d:
      if k not in result and d[k] is not None:
        result[k] = d[k]
  return result

Este utiliza una estrategia de combinación que es sólo para recoger el primer partido actual de cada grupo nombrado en el patrón. Ahora por ejemplo

>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')
{'i': 'hij', 'b': 'abc'}
>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'[::-1])
{'i': 'jih', 'b': 'cba'}

presumiblemente como usted desea, si interpreto bien su pregunta.

Otros consejos

>>> [m.groupdict() for m in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

Parece que funcionan bien, aunque si tiene muchos grupos de verificación, que uno no es None podría resultar tedioso.

Esto encuentra todos .b. y todos los partidos .i. en la cadena. Si usted quiere estar seguro de que uno encuentra cada uno de ustedes tendrá que comprobar manualmente, también.

Lo más cerca que puedo conseguir es la siguiente:

>>> [match.groupdict() for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]

¿Cómo se combinan los diccionarios entonces depende de si usted está esperando más de una coincidencia. Si sólo desea un partido cada uno, se puede hacer:

>>> results = {}
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'):
...     results.update(dict((k,v) for k, v in match.groupdict().iteritems() if v is not None))
... 
>>> results
{'i': 'hij', 'b': 'abc'}

O para varias coincidencias:

>>> results = defaultdict(lambda: [])
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijkabcdefghijk'):
...     for k, v in match.groupdict().iteritems():
...         if v is not None:
...             results[k].append(v)
... 
>>> results
defaultdict(<function <lambda> at 0x7f53d0992c08>, {'i': ['hij', 'hij'], 'b': ['abc', 'abc']})

Esta es una manera que no requiere ni finditer fusión diccionario:

>>> pat = re.compile(r'(?:.*?(?:(?P<b>.b.)|(?P<i>.i.))){2}')

>>> pat.search('abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

>>> pat.search('aicdefghbjk').groupdict()
{'i': 'aic', 'b': 'hbj'}

Esto es asumiendo cada uno de los personajes y b i aparece exactamente una vez en su cadena, de otro modo:

  • Si uno de los personajes podría hacer falta, se puede utilizar en lugar de {,2} {2}.
  • Si uno de los personajes aparece más de una vez, la búsqueda recuperará las dos primeras apariciones de o bien de ellos (por ejemplo, se puede encontrar b dos veces y no encontrar i en absoluto).

Aquí es un recién llegado al juego de un golpe, que es legible para los principiantes también:

>>> dict([(name, re.search(pattern, "abcdefghijk").group())
          for name, pattern in {"b": ".b.", "i": ".i"}.items()])  
{'b': 'abc', 'i': 'hij'}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top