Rückgabezeichenfolge mit der ersten Übereinstimmung Regex

90

Ich möchte das erste Match einer Regex bekommen.

In diesem Fall habe ich eine Liste bekommen:

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

['33', '44']

Ich könnte das erste Element der Liste extrahieren:

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

'33'

Das funktioniert aber nur, wenn es mindestens eine Übereinstimmung gibt, sonst wird eine Fehlermeldung angezeigt:

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

IndexError: Listenindex außerhalb des Bereichs

In diesem Fall könnte ich eine Funktion definieren:

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

Gibt es eine Möglichkeit, dieses Ergebnis zu erhalten, ohne eine neue Funktion zu definieren?

Luis Ramon Ramirez Rodriguez
quelle
Für mich hat die akzeptierte Antwort nicht funktioniert. Ich musste den Array-Indexzugriff entfernen und len(re.findAll)==0stattdessen check verwenden.
Vishal

Antworten:

105

Sie können die ''Standardeinstellung in Ihre Regex einbetten, indem Sie Folgendes hinzufügen |$:

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

Funktioniert auch mit re.searchvon anderen hervorgehobenen:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''
Stefan Pochmann
quelle
Großartig, hat search / .group einen Vorteil gegenüber findall / [0]?
Luis Ramon Ramirez Rodriguez
6
@LuisRamonRamirezRodriguez Nun, es kann aufhören, sobald es eine Übereinstimmung gefunden hat, muss den Rest des Textes nicht verarbeiten und muss nicht alle Übereinstimmungen speichern. Es ist also effizienter. Außerdem ist es buchstäblich "das, was Sie wollen" , wie @TimPeters sagte. Das könnte ein Vorteil sein, wenn Sie oder jemand anderes es irgendwann lesen und sich fragen: "Warum wurde es findallverwendet?" .
Stefan Pochmann
43

Wenn Sie nur das erste Spiel benötigen, verwenden Sie re.searchanstelle von 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'

Dann können Sie mals Prüfbedingung Folgendes verwenden:

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


First number found = 33
Eisenfaust
quelle
13

Ich würde gehen mit:

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

re.searchsucht sowieso nur nach der ersten Übereinstimmung in der Zeichenfolge, daher denke ich, dass dies Ihre Absicht etwas klarer macht als die Verwendung findall.

Rechnung
quelle
7

Sie sollten überhaupt nicht verwenden .findall()- .search()ist das, was Sie wollen. Es findet die Übereinstimmung ganz links, die Sie möchten (oder gibt zurück, Nonewenn keine Übereinstimmung vorhanden ist).

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

Ob Sie das in eine Funktion einfügen möchten, liegt bei Ihnen. Es ist ungewöhnlich , eine leere Zeichenfolge zurückgeben zu wollen, wenn keine Übereinstimmung gefunden wird, weshalb nichts dergleichen eingebaut ist. Es ist unmöglich, sich darüber zu verwirren, ob .search()allein eine Übereinstimmung gefunden wird (sie wird zurückgegeben, Nonewenn dies nicht der Fall ist , oder ein SRE_MatchObjekt wenn ja).

Tim Peters
quelle
3

Du kannst tun:

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

Beachten Sie, dass Ihre Frage nicht genau mit Regex zusammenhängt. Wie finden Sie ein Element aus einem Array sicher, wenn es keines hat?

ketan vijayvargiya
quelle
2
Ich würde 'len (x)> 0' hier einfach durch 'x' ersetzen.
Ulf Aslak
1

Vielleicht würde dies etwas besser funktionieren, wenn eine größere Menge an Eingabedaten Ihr gewünschtes Stück nicht enthält, da dies nur höhere Kosten verursacht.

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