W Perl kwantyfikatory w wyrażeniach regularnych – *, +, ?, {n,m} – domyślnie są chciwe (greedy): łapią maksymalną możliwą ilość znaków, które pasują do wzorca.
Dodanie ? po kwantyfikatorze przekształca go w leniwy (lazy lub non-greedy): łapie minimalną możliwą ilość znaków, aby całe wyrażenie regularne było zgodne.
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*>/; # Złapie '<bar> baz <quux>'
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*?>/; # Złapie '<bar>'
Chciwe wyrażenie może „zjeść” więcej niż się spodziewasz podczas parsowania HTML i innych zagnieżdżonych konstrukcji!
Czym różnią się poniższe dwa wyrażenia regularne podczas analizy ciągu
<a><b><c>:/<(.*)>/i/<(.*?)>/?
Odpowiedź:
/<(.*)>/ (chciwe) złapie maksymalny blok – dopasowanie: <a><b><c>/<(.*?)>/ (leniwy) – tylko pierwsza grupa: <a>Przykład:
my $s = '<a><b><c>'; $s =~ /<(.*)>/; # $1: 'a><b><c' $s =~ /<(.*?)>/; # $1: 'a'
Historia
W aplikacji do importowania nagłówków wiadomości programista chciał sparsować nazwę tagu w ciągu
<title>Nowość</title>, używając/\<(.*)\>/. W rezultacie wyrażenie regularne łapało cały ciąg między<pierwszym a>ostatnim, a nie potrzebny element. Błąd został znaleziony, gdy pojawiły się zagnieżdżone tagi.
Historia
W parserze logicznym do wydobywania cytowanych ciągów użyty wzór
/"(.*)"/niespodziewanie łapał wszystko między pierwszym a ostatnim cudzysłowem. W rezultacie formatowanie było niepoprawnie łamane, dopóki nie zamieniono wzoru na/"(.*?)"/.
Historia
W automatycznym parserze CSV z możliwością cudzysłowów był źle napisany wzór na „chciwość”, przez co kilka kolumn łączyło się w jedną. Błąd wprowadzony przez parser ujawnił się dopiero na dużych danych – leniwa modyfikacja wzoru rozwiązała problem.