
Correspondência «greedy» vs «lazy» em expressões regulares: por que é que o seu padrão abrange demasiado
Publicado em 24 de jul. de 2026
Escreve <b>.*</b> para extrair o conteúdo de uma tag em negrito, testa-o em <b>Hello</b> e funciona na perfeição. Depois, executa-o em HTML real com duas tags de negrito na mesma linha — <b>Hello</b> and <b>World</b> — e, em vez de duas correspondências, obtém uma correspondência gigante que abrange ambas as tags. Isto não é um bug no seu motor de expressões regulares; é o comportamento predefinido de *, + e {n,m}, e tem uma correção de um único caractere assim que perceber o que está a acontecer.
Por que é que o .* captura mais do que o esperado
Por predefinição, os quantificadores nas expressões regulares são gulosos — o .* não significa «encontrar alguns caracteres», significa «encontrar o máximo de caracteres possível e, só então, recuar se o resto do padrão o exigir absolutamente».
Analisemos o <b>.*</b> em comparação com o <b>Hello</b> and <b>World</b>, passo a passo:
<b>corresponde ao primeiro<b>..*começa por consumir todo o resto da cadeia — tudo até ao fim, incluindo o segundo<b>World</b>.- O motor precisa então de encontrar o
</b>para concluir a correspondência, pelo que começa a recuar a partir do fim do.*, um carácter de cada vez. - O primeiro local (analisando para trás a partir do fim) onde o
</b>se encaixa é o último</b>da cadeia — e não o primeiro onde «logicamente» deveria parar.
Assim, a correspondência acaba por ser «<b>Hello</b> and <b>World</b>» na sua totalidade, porque a correspondência gananciosa tenta sempre primeiro a sequência mais longa possível e só a reduz o mínimo necessário para que o resto do padrão seja bem-sucedido.
A correção: tornar o quantificador preguiçoso com ?
Adicionar um ? imediatamente após um quantificador transforma-o de ganancioso em preguiçoso (também chamado de «não ganancioso» ou «relutante»): *?, +?, ??, {n,m}?.
Um quantificador preguiçoso faz o oposto: começa por corresponder o menor número possível de caracteres e só se expande se o resto do padrão ainda não puder ser correspondido.
<b>.*?</b> aplicado à mesma cadeia:
<b>corresponde ao primeiro<b>..*?começa por corresponder a zero caracteres.- O motor verifica: será que o
</b>corresponde aqui? Não (estamos em «Hello…», ainda não num</b>) — por isso, expande o.*?em exatamente um carácter e verifica novamente. - Isto repete-se caractere a caractere até que o
.*?tenha consumido exatamente oHello, altura em que o</b>corresponde imediatamente.
Resultado: <b>Hello</b> e <b>World</b> são devolvidos como duas correspondências separadas, o que é quase sempre o que se pretende ao analisar estruturas do tipo «tag» ou delimitadoras.
Quando se pretende realmente a análise gananciosa (não é apenas «o padrão errado»)
A análise gananciosa não é um erro na linguagem — é correta para um caso diferente, igualmente comum: corresponder ao limite mais externo de algo, e não à menor unidade no seu interior. Se estiver a extrair «tudo o que está entre o primeiro { e o último } » num bloco de texto semelhante a JSON (por exemplo, para obter um objeto completo, independentemente do aninhamento), o modo «greedy» é exatamente o correto, enquanto o modo «lazy» pararia no primeiro } interno, resultando num fragmento truncado e inválido.
Regra geral: «lazy» para pequenos blocos delimitados repetidos (etiquetas, cadeias entre aspas, itens de lista); «greedy» para «capturar todo o intervalo exterior».
Referência rápida
| Padrão | Comportamento | Utilizar quando |
|---|---|---|
.*, .+, {n,m} |
Greedy — corresponde ao mais longo possível | Pretende o span mais externo, ou existe apenas uma correspondência na cadeia de caracteres |
.*?, .+?, {n,m}? |
Preguiçoso — corresponde ao mais curto possível | Tem vários blocos delimitados semelhantes e pretende cada um separadamente |
Se não tiver a certeza de qual das abordagens um padrão está realmente a utilizar na sua entrada real, em vez da sua cadeia de teste, execute-o no texto real com correspondências múltiplas num testador de expressões regulares com realce de correspondências em tempo real torna a diferença imediatamente visível — verá um único bloco gigante realçado no caso do modo «greedy», em comparação com vários blocos separados no modo «lazy», o que é normalmente mais rápido do que analisar caractere a caractere.