restituisce la stringa con la prima corrispondenza Regex


91

Voglio ottenere la prima corrispondenza di una regex.

In questo caso, ho una lista:

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

["33", "44"]

Potrei estrarre il primo elemento della lista:

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

"33"

Ma funziona solo se c'è almeno una corrispondenza, altrimenti riceverò un errore:

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

IndexError: elenca l'indice fuori intervallo

In tal caso potrei definire una funzione:

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

C'è un modo per ottenere quel risultato senza definire una nuova funzione?


Per me la risposta accettata non ha funzionato. Ho dovuto rimuovere l'accesso all'indice dell'array e utilizzare len(re.findAll)==0invece il controllo.
Vishal

Risposte:


109

Puoi incorporare l' ''impostazione predefinita nella tua regex aggiungendo |$:

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

Funziona anche con re.searchsegnalati da altri:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''

Ottimo, search / .group ha qualche vantaggio rispetto a findall / [0]?
Luis Ramon Ramirez Rodriguez

6
@LuisRamonRamirezRodriguez Beh, può fermarsi non appena trova una corrispondenza, non deve elaborare il resto del testo e non deve memorizzare tutte le corrispondenze. Quindi è più efficiente. Inoltre, letteralmente "è quello che vuoi" , come ha detto @TimPeters. Questo potrebbe essere un vantaggio quando tu o qualcun altro a un certo punto lo leggete e vi chiedete "Perché è stato findallusato?" .
Stefan Pochmann

43

Se hai bisogno solo della prima corrispondenza, usa re.searchinvece di 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'

Quindi puoi usare mcome condizione di controllo come:

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


First number found = 33

13

Andrei con:

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

re.searchcerca comunque solo la prima corrispondenza nella stringa, quindi penso che renda il tuo intento leggermente più chiaro rispetto all'uso findall.


9

Non dovresti usare .findall()affatto - .search()è quello che vuoi. Trova la corrispondenza più a sinistra, che è ciò che desideri (o restituisce Nonese non esiste alcuna corrispondenza).

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

Se vuoi metterlo in una funzione dipende da te. È insolito voler restituire una stringa vuota se non viene trovata alcuna corrispondenza, motivo per cui nulla del genere è integrato. È impossibile confondersi sul fatto che .search()da solo trovi una corrispondenza (restituisce Nonese non lo ha fatto, o un SRE_Matchoggetto se lo ha fatto).


3

Tu puoi fare:

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

Tieni presente che la tua domanda non è esattamente correlata alla regex. Piuttosto, come trovare in sicurezza un elemento da un array, se non ne ha.


2
Sostituirei "len (x)> 0" con semplicemente "x" qui.
Ulf Aslak

1

Forse questo funzionerebbe un po 'meglio nel caso in cui una maggiore quantità di dati di input non contenga il pezzo desiderato perché tranne ha un costo maggiore.

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.