Regular Expressions
Chciwe i leniwe kwantyfikatory
Szukaj…
Parametry
Kwantyfikatory | Opis |
---|---|
? | Dopasuj poprzedni znak lub podwyrażenie 0 lub 1 razy (najlepiej 1). |
* | Dopasuj poprzedni znak lub podwyrażenie 0 lub więcej razy (jak najwięcej). |
+ | Dopasuj poprzedni znak lub podwyrażenie 1 lub więcej razy (jak najwięcej). |
{n} | Dopasuj poprzedni znak lub podwyrażenie dokładnie n razy. |
{min,} | Dopasuj poprzedni znak lub podwyrażenie min lub więcej razy (tyle, ile to możliwe). |
{0,max} | Dopasuj poprzedni znak lub podwyrażenie maksymalnie lub mniej razy (jak najbliżej maksimum, jak to możliwe). |
{min,max} | Dopasuj poprzedni znak lub podwyrażenie co najmniej min razy, ale nie więcej niż maksimum razy (jak najbliżej maksimum, jak to możliwe). |
Leniwe kwantyfikatory | Opis |
?? | Dopasuj poprzedni znak lub podwyrażenie 0 lub 1 razy (najlepiej 0). |
*? | Dopasuj poprzedni znak lub podwyrażenie 0 lub więcej razy (możliwie jak najmniej). |
+? | Dopasuj poprzedni znak lub podwyrażenie 1 lub więcej razy (tak mało, jak to możliwe). |
{n}? | Dopasuj poprzedni znak lub podwyrażenie dokładnie n razy. Bez różnicy między wersją chciwą a leniwą. |
{min,}? | Dopasuj poprzedni znak lub podwyrażenie min lub więcej razy (jak najbliżej min, jak to możliwe). |
{0,max}? | Dopasuj poprzedni znak lub podwyrażenie maksymalnie lub mniej razy (możliwie jak najmniej). |
{min,max}? | Dopasuj poprzedni znak lub podwyrażenie co najmniej min razy, ale nie więcej niż maksimum razy (możliwie jak najbliżej min ). |
Uwagi
Łakomstwo
Chciwy kwantyfikator zawsze próbuje powtórzyć pod-wzór tyle razy, ile to możliwe, przed zbadaniem krótszych dopasowań poprzez cofanie.
Zasadniczo chciwy wzór będzie pasował do jak najdłuższego ciągu.
Domyślnie wszystkie kwantyfikatory są zachłanne.
Lenistwo
Leniwy (zwany także niechcianym lub niechętnym ) kwantyfikator zawsze próbuje powtórzyć pod-wzór tak mało razy, jak to możliwe, przed badaniem dłuższych dopasowań przez rozwinięcie.
Ogólnie rzecz biorąc, leniwy wzór będzie pasował do możliwie najkrótszego ciągu.
Aby sprawić, by kwantyfikatory były leniwe, po prostu dodaj ?
do istniejącego kwantyfikatora, np. +?
, {0,5}?
.
Pojęcie chciwości i lenistwa istnieje tylko w silnikach wycofujących
Pojęcie chciwego / leniwego kwantyfikatora istnieje tylko w silnikach wyrażeń zwrotnych. W silnikach wyrażeń regularnych bez śledzenia lub silnikach wyrażeń zgodnych z POSIX kwantyfikatory określają tylko górną i dolną granicę powtórzenia, bez określania, jak znaleźć dopasowanie - te silniki zawsze będą pasować do najdłuższego łańcucha po lewej stronie, niezależnie od tego.
Chciwość kontra lenistwo
Biorąc pod uwagę następujące dane wejściowe:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
Użyjemy dwóch wzorów: jeden chciwy: A.*Z
, a drugi leniwy: A.*?Z
Te wzorce dają następujące dopasowania:
-
A.*Z
daje 1 dopasowanie:AlazyZgreeedyAlaaazyZ
(przykłady: Regex101 , Rubular ) -
A.*?Z
daje 2 dopasowania:AlazyZ
iAlaaazyZ
(przykłady: Regex101 , Rubular )
Najpierw skup się na tym, co robi A.*Z
Gdy pasuje do pierwszego A
,. .*
, Będąc zachłannym, próbuje dopasować tyle samo .
jak to możliwe.
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\________________________/
A.* matched, Z can't match
Ponieważ Z
nie pasuje, cewki silnika i .*
Muszą następnie pasować o jeden mniej .
:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\_______________________/
A.* matched, Z can't match
Dzieje się to jeszcze kilka razy, aż w końcu do tego dojdzie:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\__________________/
A.* matched, Z can now match
Teraz Z
może się zgadzać, więc ogólny wzór pasuje:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\___________________/
A.*Z matched
Natomiast niechętne (leniwe) powtarzanie w A.*?Z
najpierw pasuje do kilku .
jak to możliwe, a następnie biorąc więcej .
jako niezbędne. To wyjaśnia, dlaczego znajduje dwa dopasowania w danych wejściowych.
Oto wizualna reprezentacja dopasowania dwóch wzorów:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\____/l \______/l l = lazy
\_________g_________/ g = greedy
Przykład oparty na odpowiedzi udzielonej przez wieloskładnikowe środki smarujące .
Standard POSIX nie obejmuje ?
operator, tak wiele silników wyrażeń regularnych POSIX nie ma leniwego dopasowania. Podczas gdy refaktoryzacja, szczególnie w przypadku „największej sztuczki w historii” , może w niektórych przypadkach pomóc w dopasowaniu, jedynym sposobem na prawdziwe leniwe dopasowanie jest użycie silnika, który ją obsługuje.
Granice z wieloma dopasowaniami
Jeśli masz dane wejściowe z dobrze zdefiniowanymi granicami i oczekujesz więcej niż jednego dopasowania w ciągu, masz dwie opcje:
- Korzystanie z leniwych kwantyfikatorów;
- Używanie zanegowanej klasy postaci.
Rozważ następujące:
Masz prosty silnik szablonów, chcesz zastąpić podciągi takie jak $[foo]
gdzie foo
może być dowolnym ciągiem. Chcesz zamienić ten podciąg na cokolwiek opartego na części między []
.
Możesz spróbować czegoś takiego jak \$\[(.*)\]
, A następnie użyć pierwszej grupy przechwytywania.
Problem polega na tym, że jeśli masz ciąg taki jak something $[foo] lalala $[bar] something else
będzie pasować
something $[foo] lalala $[bar] something else
| \______CG1______/|
\_______Match______/
Grupa przechwytująca to foo] lalala $[bar
która może, ale nie musi być poprawna.
Masz dwa rozwiązania
Używanie lenistwa: w tym przypadku
*
leniwość jest jednym ze sposobów na znalezienie właściwych rzeczy. Więc zmieniasz wyrażenie na\$\[(.*?)\]
Używając zanegowanej klasy znaków:
[^\]]
zmieniasz wyrażenie na\$\[([^\]]*)\]
.
W obu rozwiązaniach wynik będzie taki sam:
something $[foo] lalala $[bar] something else
| \_/| | \_/|
\____/ \____/
Grupa przechwytywania to odpowiednio foo
i bar
.
Używanie zanegowanej klasy znaków zmniejsza problem cofania się i może zaoszczędzić dużo czasu procesorowi, jeśli chodzi o duże nakłady.