Ograniczanie zachłanności w wyrażeniach regularnych w PHP
Wyrażenia regularne domyślnie są zachłanne. Oznacza to, że przechwytują maksymalną możliwą liczbę znaków.
Przeanalizujmy to na przykładzie. Załóżmy, że mamy taki ciąg znaków:
<?php
$str = 'aeeex zzz x kkk';
?>
Załóżmy, że w tym ciągu chcemy znaleźć podciąg
'aeeex' według następującego wzorca: litera
'a', następnie dowolny znak jeden lub więcej
razy, następnie litera 'x'.
<?php
$res = preg_replace('#a.+x#', '!', $str);
?>
Oczekujemy, że do zmiennej w wyniku
zostanie zapisany ciąg '! zzz x kkk'. Jednakże,
tak nie jest - do zmiennej trafia ciąg
'! kkk'.
Chodzi o to, że nasze wyrażenie regularne szuka wszystkich
znaków od litery 'a' do litery 'x'.
Ale w naszym ciągu są dwie litery 'x'. Z powodu
zachłanności okazuje się, że wyrażenie regularne szuka do
ostatniego 'x', tym samym przechwytując
nie to, czego oczekiwaliśmy.
Oczywiście, często takie zachowanie jest właśnie tym, czego potrzebujemy. Ale konkretnie w tym przypadku chcielibyśmy wyłączyć zachłanność i powiedzieć wyrażeniu regularnemu, żeby szukało do pierwszego 'x'.
Aby ograniczyć zachłanność, należy po operatorze powtórzenia postawić znak zapytania:
<?php
$res = preg_replace('#a.+?x#', '!', $str);
?>
Zachłanność można ograniczać wszystkim operatorom
powtórzeń, w ten sposób: *?, ??
i {}?.
Dany jest ciąg:
<?php
$str = 'aba accca azzza wwwwa';
?>
Napisz wyrażenie regularne, które znajdzie wszystkie ciągi
na których końcach stoją litery 'a',
i zastąpi każdy z nich na '!'. Między
literami a może być dowolny znak (oprócz
'a').