Em ganancioso vs não ganancioso
A repetição na regex, por padrão, é gananciosa : eles tentam corresponder o máximo de repetições possível e, quando isso não funciona e precisam voltar, tentam corresponder a menos um representante de cada vez, até que uma correspondência de todo o padrão seja encontrado. Como resultado, quando uma partida finalmente acontece, uma repetição gananciosa corresponderá ao maior número possível de representantes.
O ?quantificador de repetição muda esse comportamento para não ganancioso , também chamado de relutante ( em Java, por exemplo ) (e às vezes "preguiçoso"). Em contraste, esta repetição vai primeiro tentar igualar como alguns representantes quanto possível, e quando isso não funciona e eles têm que voltar atrás, eles começam a correspondência mais uma rept um tempo. Como resultado, quando uma partida finalmente acontece, uma repetição relutante corresponderia ao menor número de repetições possível.
Referências
Exemplo 1: de A a Z
Vamos comparar esses dois padrões: A.*Ze A.*?Z.
Dada a seguinte entrada:
eeeAiiZuuuuAoooZeeee
Os padrões produzem as seguintes correspondências:
Vamos primeiro nos concentrar no que A.*Zfaz. Quando combinou com o primeiro A, o .*, sendo ganancioso, primeiro tenta combinar o maior número .possível.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Como Znão corresponde, o mecanismo retorna e .*deve corresponder a menos um .:
eeeAiiZuuuuAoooZeeee
\______________/
A.* matched, Z still can't match
Isso acontece mais algumas vezes, até que finalmente chegamos a isso:
eeeAiiZuuuuAoooZeeee
\__________/
A.* matched, Z can now match
Agora Zpode corresponder, portanto, o padrão geral corresponde:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
Por outro lado, a repetição relutante nos A.*?Zprimeiros jogos corresponde ao .mínimo possível e, em seguida, leva o .máximo que for necessário. Isso explica por que ele encontra duas correspondências na entrada.
Aqui está uma representação visual do que os dois padrões corresponderam:
eeeAiiZuuuuAoooZeeee
\__/r \___/r r = reluctant
\____g____/ g = greedy
Exemplo: uma alternativa
Em muitas aplicações, as duas correspondências na entrada acima são o que se deseja, portanto, um relutante .*?é usado no lugar do ganancioso .*para evitar a superação. Para esse padrão específico, no entanto, existe uma alternativa melhor, usando a classe de caracteres negada.
O padrão A[^Z]*Ztambém encontra as mesmas duas correspondências que o A.*?Zpadrão para a entrada acima ( como visto em ideone.com ). [^Z]é o que é chamado de classe de caracteres negada : corresponde a qualquer coisa, menos Z.
A principal diferença entre os dois padrões está no desempenho: sendo mais rigorosa, a classe de caracteres negados pode corresponder apenas a um caminho para uma determinada entrada. Não importa se você usa modificador ganancioso ou relutante para esse padrão. De fato, em alguns sabores, você pode se sair ainda melhor e usar o que é chamado de quantificador possessivo, que não retrocede.
Referências
Exemplo 2: de A a ZZ
Este exemplo deve ser ilustrativo: mostra como os padrões de classe de caracteres gananciosos, relutantes e negados são diferentes de acordo com a mesma entrada.
eeAiiZooAuuZZeeeZZfff
Estas são as correspondências para a entrada acima:
Aqui está uma representação visual do que eles corresponderam:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
tópicos relacionados
Esses são links para perguntas e respostas no stackoverflow que cobrem alguns tópicos que podem ser do seu interesse.
Uma repetição gananciosa pode superar outra