Limitação da ganância em expressões regulares no PHP
As expressões regulares são gananciosas por padrão. Isso significa que elas capturam o número máximo possível de caracteres.
Vamos analisar um exemplo. Suponha que temos a seguinte string:
<?php
$str = 'aeeex zzz x kkk';
?>
Suponha que nesta string queremos encontrar a substring
'aeeex' usando o seguinte padrão: a letra
'a', seguida por qualquer caractere uma ou mais
vezes, seguida pela letra 'x'.
<?php
$res = preg_replace('#a.+x#', '!', $str);
?>
Esperamos que o resultado na variável seja
a string '! zzz x kkk'. No entanto,
não é isso que acontece - a string que acaba na variável
é '! kkk'.
O problema é que nossa expressão regular busca todos
os caracteres da letra 'a' até a letra 'x'.
Mas na nossa string existem duas letras 'x'. Devido
à ganância, a regex busca até o último 'x',
acabando por capturar algo diferente do que esperávamos.
Claro, muitas vezes esse comportamento é exatamente o que precisamos. Mas, neste caso específico, gostaríamos de desativar a ganância e instruir a regex a buscar até o primeiro 'x'.
Para limitar a ganância, é necessário colocar um ponto de interrogação após o operador de repetição:
<?php
$res = preg_replace('#a.+?x#', '!', $str);
?>
A ganância pode ser limitada para todos os operadores
de repetição, assim: *?, ??
e {}?.
Dada a string:
<?php
$str = 'aba accca azzza wwwwa';
?>
Escreva uma expressão regular que encontre todas as strings
delimitadas pela letra 'a',
e substitua cada uma delas por '!'. Entre
as letras 'a' pode haver qualquer caractere (exceto
'a').