CodeKitHub
Português
Correspondência «greedy» vs «lazy» em expressões regulares: por que é que o seu padrão abrange demasiado

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:

  1. <b> corresponde ao primeiro <b>.
  2. .* começa por consumir todo o resto da cadeia — tudo até ao fim, incluindo o segundo <b>World</b>.
  3. 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.
  4. 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:

  1. <b> corresponde ao primeiro <b>.
  2. .*? começa por corresponder a zero caracteres.
  3. 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.
  4. Isto repete-se caractere a caractere até que o .*? tenha consumido exatamente o Hello, 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.

← Voltar ao blog