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.*Z
e A.*?Z
.
Dada a seguinte entrada:
eeeAiiZuuuuAoooZeeee
Os padrões produzem as seguintes correspondências:
Vamos primeiro nos concentrar no que A.*Z
faz. 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 Z
nã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 Z
pode corresponder, portanto, o padrão geral corresponde:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
Por outro lado, a repetição relutante nos A.*?Z
primeiros 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]*Z
também encontra as mesmas duas correspondências que o A.*?Z
padrã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