2013-05-19 21 views
6

Mam regex .net, które testuję przy użyciu Powershell systemu Windows. Wyjście jest w następujący sposób:Kwantyfikator non-chciwy regex daje chciwy wynik

> [System.Text.RegularExpressions.Regex]::Match("aaa aaa bbb", "aaa.*?bbb") 


Groups : {aaa aaa bbb} 
Success : True 
Captures : {aaa aaa bbb} 
Index : 0 
Length : 11 
Value : aaa aaa bbb 

Moje oczekiwanie było to, że za pomocą ? kwantyfikator spowoduje, że mecz będzie aaa bbb, a druga grupa A jest wystarczająca do zaspokojenia wyraz. Czy moje rozumienie błędnych kwantyfikatorów jest błędne, czy też testuję je nieprawidłowo?

Uwaga: to nie jest po prostu taki sam problem jak Regular Expression nongreedy is greedy

Odpowiedz

5

Jest to typowe nieporozumienie. Leniwe kwantyfikatory nie gwarantują najkrótszego możliwego dopasowania. Dbają tylko o to, aby obecny kwantyfikator z obecnej pozycji nie pasował do większej liczby znaków niż jest to konieczne do dopasowania ogólnego.

Jeśli naprawdę chcesz zapewnić możliwie najkrótsze dopasowanie, musisz to sprecyzować. W tym przypadku oznacza to, że zamiast .*?, chcesz subregex pasujący do wszystkiego, co nie jest ani aaa ani bbb. Wynikowe wyrażenie będzie zatem następujące:

aaa(?:(?!aaa|bbb).)*bbb 
+0

Po prostu zrobiłem to, co powinienem był zrobić i skonsultowałem się z odpowiednim rozdziałem Friedla. To doprowadziło mnie do 'aaa ((?! Aaa).) * Bbb', co jest mniej więcej tym, co powiedziałeś, z tą różnicą, że twoja odpowiedź zawiera dodatkowe szczegóły, które powodują, że podwyrażenia nie są przechwytywane, a także testy dla bbb w negatywie. patrz przed siebie. Niezła odpowiedź. –

5

Porównać wynik dla ciągu aaa aaa bbb bbb:

regex: aaa.*?bbb 
result: aaa aaa bbb 

regex: aaa.*bbb 
result: aaa aaa bbb bbb 

Silnik regex znajdzie pierwsze wystąpienie aaa i następnie pomija wszystkie znaki (.*?) do po raz pierwszy wystąpienie bbb, ale dla chciwego operatora (.*) przejdzie on dalej, aby znaleźć większy wynik i dlatego pasuje do t wystąpienie bbb.

+0

To jest najjaśniejsze wyjaśnienie tego, co się dzieje. +1 – duozmo

0

Cóż to naprawdę proste, mamy następujący ciąg

aaa aaa bbb

Zobaczmy mamy ten regex aaa.*?bbb. Silnik regex rozpocznie aaa

aaa aaa bbb

silnik regex ma teraz .*?bbb. Będzie kontynuować space

aaa przestrzeni aaa bbb

ale wciąż mamy kilka znaków aż bbb? Więc silnik regex będzie nadal to sposób i dopasować drugi zestaw w

aaa przestrzeni aaa bbb

Wreszcie silnik regex będą pasować bbb:

aaa aaa bbb


Zobaczmy więc, jeśli chcemy tylko, aby dopasować drugie aaa możemy użyć następującego wyrażenia regularnego:

(?<!^)aaa.*?bbb oznacza to, aby dopasować aaa, który nie jest na początku zdania.

Możemy również użyć aaa(?= bbb).*?bbb, to znaczy, aby dopasować aaa, po którym następuje space bbb.

Zobacz pracuje 1 - 2.

Właśnie odzyskałem zmysły, ale dlaczego nie używasz bezpośrednio aaa bbb?

1

To nie jest chciwy/leniwy problem. Problem polega na tym, że twój ciąg jest analizowany od lewej do prawej. Gdy pierwszy dopasowany aaa jest dopasowany, silnik regex dodaje znaki jeden po drugim, aby uzyskać pełny wzór.

Należy zauważyć, że przy zachowaniu zachłannym, w twoim przykładzie, otrzymujesz taki sam wynik: pierwszy dopasowany jest aaa, silnik regex bierze wszystkie ostatnie znaki i odtwarza znak po znaku, aż do pełnego dopasowania.

Powiązane problemy