zwracany ciąg z pierwszym dopasowaniem Regex


90

Chcę uzyskać pierwsze dopasowanie wyrażenia regularnego.

W tym przypadku mam listę:

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

[„33”, „44”]

Mógłbym wyodrębnić pierwszy element listy:

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

„33”

Ale to działa tylko wtedy, gdy jest co najmniej jedno dopasowanie, w przeciwnym razie otrzymam błąd:

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

IndexError: indeks listy poza zakresem

W takim przypadku mógłbym zdefiniować funkcję:

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

Czy istnieje sposób uzyskania tego wyniku bez definiowania nowej funkcji?


Dla mnie zaakceptowana odpowiedź nie zadziałała. Musiałem usunąć dostęp do indeksu tablicy i len(re.findAll)==0zamiast tego użyć sprawdzenia.
Vishal

Odpowiedzi:


104

Możesz osadzić ''domyślne w swoim wyrażeniu regularnym, dodając |$:

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

Działa również ze re.searchwskazanymi przez innych:

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

Świetnie, czy search / .group ma jakąś przewagę nad findall / [0]?
Luis Ramon Ramirez Rodriguez

6
@LuisRamonRamirezRodriguez Cóż, może się zatrzymać, gdy tylko znajdzie dopasowanie, nie musi przetwarzać reszty tekstu i nie musi przechowywać wszystkich dopasowań. Więc jest bardziej wydajny. Ponadto, dosłownie „jest tym, czego chcesz” , jak powiedział @TimPeters. Może to być zaletą, gdy Ty lub ktoś inny w pewnym momencie go przeczytacie i zaczniecie się zastanawiać: „Dlaczego został findallużyty?” .
Stefan Pochmann

43

Jeśli potrzebujesz tylko pierwszego dopasowania, użyj re.searchzamiast 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'

Następnie możesz użyć mjako warunku sprawdzającego jako:

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


First number found = 33

12

Poszedłbym z:

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

re.searchi tak szuka tylko pierwszego dopasowania w ciągu, więc myślę, że dzięki temu twój zamiar jest nieco bardziej jasny niż użycie findall.


7

W ogóle nie powinieneś używać .findall()- .search()tego chcesz. Znajduje najbardziej lewe dopasowanie, które jest tym, czego chcesz (lub zwraca, Nonejeśli dopasowanie nie istnieje).

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

To, czy chcesz to umieścić w funkcji, zależy od Ciebie. To niezwykłe chce powrócić pusty ciąg, jeśli nie zostanie znaleziony, dlatego nic takiego, który jest wbudowany w. Jest to niemożliwe, aby dostać mylić o tym, czy .search()na własnych znalezisk mecz (zwraca Nonejeśli nie, albo SRE_Matchprzedmiot jeśli tak).


3

Możesz to zrobić:

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

Zwróć uwagę, że Twoje pytanie nie jest dokładnie związane z wyrażeniem regularnym. Raczej, jak bezpiecznie znaleźć element z tablicy, jeśli go nie ma.


2
Zamieniłbym tutaj „len (x)> 0” na po prostu „x”.
Ulf Aslak

1

Może to działałoby trochę lepiej, gdyby większa ilość danych wejściowych nie zawierała poszukiwanego elementu, ponieważ ma większy koszt.

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.