Nie-chciwe wyrażenia regularne w Pythonie


150

Jak utworzyć takie wyrażenie regularne w Pythonie "(.*)", mając dane "a (b) c (d) e"dopasowania w Pythonie "b"zamiast "b) c (d"?

Wiem, że mogę użyć "[^)]"zamiast ".", ale szukam bardziej ogólnego rozwiązania, które utrzyma moje wyrażenie regularne nieco bardziej przejrzystym. Czy jest jakiś sposób, aby powiedzieć Pythonowi „hej, dopasuj to tak szybko, jak to możliwe”?

Odpowiedzi:


209

Szukasz wszechmocnego *?

Z dokumentów, Greedy versus Non-Greedy

nie-zachłanne kwalifikacyjne *?, +?, ??, lub {m,n}?[...] mecz jako mało tekstu, jak to możliwe.


Według Internet Archive, wszystko, na co wskazywał odsyłacz, to kopia dokumentacji modułu „re” w Pythonie, więc link Treya działa równie dobrze.
spiffytech

2
jaka jest popularna angielska nazwa tego *??
Trevor Boyd Smith

Znaki wieloznaczne @Trevor Boyd Smith
Serge

3
Nazywa się to kwalifikacją „non chciwy”
brunetton

65
>>> x = "a (b) c (d) e"
>>> re.search(r"\(.*\)", x).group()
'(b) c (d)'
>>> re.search(r"\(.*?\)", x).group()
'(b)'

Według dokumentów :

Kwalifikatory „ *”, „ +” i „ ?” są chciwe; dopasowują jak najwięcej tekstu. Czasami takie zachowanie nie jest pożądane; jeśli RE <.*>jest dopasowany do „ <H1>title</H1>”, dopasuje cały ciąg, a nie tylko „ <H1>”. Dodanie „ ?” po kwalifikatorze sprawia, że ​​mecz przebiega w sposób niechciwy lub minimalny; dopasowanych zostanie jak najmniej znaków. Użycie .*?w poprzednim wyrażeniu spowoduje dopasowanie tylko do „ <H1>”.



5

Jak powiedzieli inni, używając? modyfikator na kwantyfikatorze * rozwiąże twój bezpośredni problem, ale bądź ostrożny, zaczynasz błądzić w obszarach, w których wyrażenia regularne przestają działać i zamiast tego potrzebujesz parsera. Na przykład napis "(foo (bar)) baz" spowoduje problemy.


5

Używanie niezbyt szczerego dopasowania to dobry początek, ale sugeruję również, abyś ponownie rozważył użycie .*- co z tym?

groups = re.search(r"\([^)]*\)", x)

3

Czy chcesz, aby pasowało do „(b)”? Zrób tak, jak sugerowali Zitrax i Paolo. Czy chcesz, aby pasowało do „b”? Robić

>>> x = "a (b) c (d) e"
>>> re.search(r"\((.*?)\)", x).group(1)
'b'

0

Na początek nie sugeruję używania „*” w wyrażeniach regularnych. Tak, wiem, jest to najczęściej używany separator wieloznakowy, ale mimo wszystko jest to zły pomysł. Dzieje się tak dlatego, że chociaż pasuje do dowolnej liczby powtórzeń dla tego znaku, „any” zawiera 0, co jest zwykle czymś, dla którego chcesz zgłosić błąd składni, a nie akceptować. Zamiast tego sugeruję użycie +znaku, który pasuje do każdego powtórzenia długości> 1. Co więcej, z tego, co widzę, masz do czynienia z wyrażeniami o stałej długości w nawiasach. W rezultacie prawdopodobnie możesz użyć {x, y}składni, aby dokładnie określić żądaną długość.

Jeśli jednak naprawdę potrzebujesz niechcianych powtórzeń, radzę skonsultować się z wszechmocnym ?. To, po umieszczeniu po na końcu dowolnego specyfikatora powtórzenia wyrażenia regularnego, zmusi tę część wyrażenia regularnego do znalezienia najmniejszej możliwej ilości tekstu.

Biorąc to pod uwagę, byłbym bardzo ostrożny z tym, ?ponieważ podobnie jak Sonic Screwdriver w Dr. Who, ma tendencję do robienia, jak mam to ująć, „lekko” niepożądanych rzeczy, jeśli nie są dokładnie skalibrowane. Na przykład, aby użyć przykładowych danych wejściowych, zidentyfikowałoby ((1)(zwróć uwagę na brak drugiego rparena) jako dopasowanie.

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.