devolver cadena con la primera coincidencia Regex

90

Quiero obtener la primera coincidencia de una expresión regular.

En este caso, tengo una lista:

text = 'aa33bbb44'
re.findall('\d+',text)

['33', '44']

Podría extraer el primer elemento de la lista:

text = 'aa33bbb44'
re.findall('\d+',text)[0]

'33'

Pero eso solo funciona si hay al menos una coincidencia, de lo contrario, obtendré un error:

text = 'aazzzbbb'
re.findall('\d+',text)[0]

IndexError: índice de lista fuera de rango

En cuyo caso podría definir una función:

def return_first_match(text):
    try:
        result = re.findall('\d+',text)[0]
    except Exception, IndexError:
        result = ''
    return result

¿Existe alguna forma de obtener ese resultado sin definir una nueva función?

Luis Ramón Ramírez Rodríguez
fuente
Para mí, la respuesta aceptada no funcionó. Tuve que eliminar el acceso al índice de la matriz y usar len(re.findAll)==0check en su lugar.
Vishal

Respuestas:

104

Puede incrustar el ''valor predeterminado en su expresión regular agregando |$:

>>> re.findall('\d+|$', 'aa33bbb44')[0]
'33'
>>> re.findall('\d+|$', 'aazzzbbb')[0]
''
>>> re.findall('\d+|$', '')[0]
''

También funciona con lo re.searchseñalado por otros:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''
Stefan Pochmann
fuente
Genial, ¿search / .group tiene alguna ventaja sobre findall / [0]?
Luis Ramon Ramirez Rodriguez
6
@LuisRamonRamirezRodriguez Bueno, puede detenerse tan pronto como encuentre una coincidencia, no tiene que procesar el resto del texto y no tiene que almacenar todas las coincidencias. Entonces es más eficiente. Además, literalmente "es lo que quieres" , como dijo @TimPeters. Eso podría ser una ventaja cuando usted u otra persona en algún momento lo lea y se pregunte "¿Por qué se findallusó?" .
Stefan Pochmann
43

Si solo necesita la primera coincidencia, utilice en re.searchlugar de re.findall:

>>> m = re.search('\d+', 'aa33bbb44')
>>> m.group()
'33'
>>> m = re.search('\d+', 'aazzzbbb')
>>> m.group()
Traceback (most recent call last):
  File "<pyshell#281>", line 1, in <module>
    m.group()
AttributeError: 'NoneType' object has no attribute 'group'

Entonces puede usar mcomo condición de verificación como:

>>> m = re.search('\d+', 'aa33bbb44')
>>> if m:
        print('First number found = {}'.format(m.group()))
    else:
        print('Not Found')


First number found = 33
Puño de hierro
fuente
12

Iría con:

r = re.search("\d+", ch)
result = return r.group(0) if r else ""

re.searchde todos modos, solo busca la primera coincidencia en la cadena, por lo que creo que deja tu intención un poco más clara que usar findall.

Cuenta
fuente
7

No deberías usar .findall()nada, .search()es lo que quieres. Encuentra la coincidencia más a la izquierda, que es lo que desea (o devuelve Nonesi no existe ninguna coincidencia).

m = re.search(pattern, text)
result = m.group(0) if m else ""

Si desea poner eso en una función, depende de usted. Es inusual querer devolver una cadena vacía si no se encuentra ninguna coincidencia, razón por la cual no se incluye nada como eso. Es imposible confundirse acerca de si .search()por sí solo encuentra una coincidencia ( Nonesi no lo hace, o un SRE_Matchobjeto si lo hizo).

Tim Peters
fuente
3

Tu puedes hacer:

x = re.findall('\d+', text)
result = x[0] if len(x) > 0 else ''

Tenga en cuenta que su pregunta no está exactamente relacionada con la expresión regular. Más bien, ¿cómo se encuentra de forma segura un elemento de una matriz, si no tiene ninguno?

ketan vijayvargiya
fuente
2
Reemplazaría 'len (x)> 0' con simplemente 'x' aquí.
Ulf Aslak
1

Tal vez esto funcione un poco mejor en caso de que una mayor cantidad de datos de entrada no contenga la pieza deseada porque, excepto, tiene un costo mayor.

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
Marko Mackic
fuente