Quantificadores

  1. Quantificadores gulosos
  2. Quantificadores preguiçosos
  3. Quantificadores possessivos

Os quantificadores determinam a quantidade permitida do item que eles precedem. Há 3 tipos de quantificadores: gulosos, preguiçosos e possessivos.

Quantificadores gulosos

Os quantificadores gulosos são chamados assim porque casam com o máximo de caracteres possível. Veja quais são eles:

  • ?: esse quantificador torna o item que o precede opcional. Exemplos: ciou? (casa com ciou e cio), ci[eo]? (casa com cie, cio e ci) e es(tr|en)? (casa com estr, esen e es).
  • *: é chamado de estrela/asterisco. Pode casar 0 ou mais vezes com o item que o precede. Exemplos: err* (casa com er, err, errrrrrr) e grande am.* (casa com grande amor, grande amigo que você fez nas férias).
  • +: é bem semelhante ao *. A diferença é que o item anterior a esse quantificador precisa estar presente pelo menos uma vez. Exemplos: err+ (casa com err, errrrrr, mas não com er), es+ (casa com es, esssss), e(r|s|a)+ (casa com er, essa, era) e p([aeiou]|r)+ (casa com pro, par, pai).
  • Intervalo: algumas engines também suportam esse quantificador. Ele especifica, entre chaves, o número mínimo de vezes que o item anterior pode aparecer, e, opcionalmente, o número máximo também. Há 3 sintaxes: {min}, {min,} e {min,max}. Há engines que suportam esse quantificador, mas suportam apenas a primeira sintaxe. Exemplos desse quantificador: r{1} (casa apenas com r), [aeiou]{2,} (casa com ai, ou, ei, aeuaeiuo), [0-9]{2,3} (casa com 390, 52) e [0-9]{4,5}-?[0-9]{4,4} (casa com um telefone celular do Brasil sem DDD. Casa tanto com telefones no formato 9999-9999, como também com telefones no formato 99999-9999).

Quantificadores preguiçosos

Os quantificadores preguiçosos tem os mesmos tipos de quantificadores que os gulosos. A diferença é que eles são expressos com um ? à frente do quantificador: *?, +?, ?? e {x,y}?.

Ao contrário dos quantificadores gulosos, os preguiçosos casam com o mínimo de caracteres possível. Esses quantificadores são um pouco difíceis de entender. Por isso, vou explicá-los de uma maneira mais detalhada.

Vamos supor que você tenha na sua string a palavra zoológico. Se você usar a expressão regular zo*, ela vai casar com zoo, porque você usou um quantificador guloso. Mas, se você usar zo*?, ela vai casar apenas com z, porque o quantificador exige que ela case com o item anterior 0 ou mais vezes, e como ele é preguiçoso, ele vai casar com o mínimo possível. Agora, se você usar zo*?lógico, ele vai casar com a palavra zoológico.

Veja que, no último exemplo, o quantificador preguiçoso casou com dois caracteres, o máximo que dava pra casar. Isso porque, se ele não fizesse isso, ele ia deixar de casar com a palavra zoológico. E pra casar com alguma coisa na string, qualquer quantificador preguiçoso abre mão da preguiça. É uma preguiça responsável :)

Outros exemplos de quantificadores preguiçosos: rou?? (casa com ro), rou??pa (casa com roupa), rou+? (casa com rou), zo+?.*o (casa com zoo, zoológico), re{1,}?.*r (casa com reinar, reerguer), .*(dor|eira)+? (casa com assento de madeira, limpador).

Quantificadores possessivos

Há também os quantificadores possessivos. Para falar sobre eles, primeiramente é preciso explicar algo que ocorre muito durante a interpretação de expressões regulares, que se chama backtracking.

Vamos supor que temos uma string com o conteúdo durante os nossos dias e a expressão regular .*e. Ela casa com a palavra durante. Temos na expressão regular um quantificador guloso e o caractere literal e. O quantificador guloso casa com o durant. Mas isso não ocorre logo no início.

Em um primeiro momento, o quantificador guloso casa com tudo, porque ele casa com o máximo de caracteres possível que atendam as suas condições. No caso, é a string toda. Só que aí, ele não consegue casar com o restante da expressão regular, que no caso é o e.

Quando a expressão regular falha e há um quantificador guloso que poderia casar com menos caracteres, esse quantificador cede um caractere. Esse processo é chamado de backtracking. Ele é feito sempre com um caractere por vez. Isso é feito porque a expressão regular não tem a inteligência de saber "de primeira" qual é o máximo de caracteres que podem casar com um quantificador guloso sem que a expressão regular falhe.

O quantificador guloso casa com o máximo de caracteres possível e cede caracteres para a engine quando ela precisar e enquanto eles puderem ceder. No exemplo citado, o quantificador guloso vai ceder caracteres até ficar apenas com durant. Quando isso ocorre, a expressão regular passa, então ela não precisa pedir mais caracteres ao quantificador.

Perceba que os quantificadores sempre cedem apenas um caractere por vez, para não correr o risco de ceder mais do que o necessário, já que eles são quantificadores gulosos, e como bons gulosos, querem comer o máximo de caracteres que puderem, mas sem deixar de cooperar com a engine.

O backtracking não acontece apenas com o quantificador estrela. Ocorre com qualquer quantificador guloso, enquanto ele puder ceder caracteres para que a expressão regular case com alguma coisa.

O backtracking também pode ocorrer em alternações. A engine para de interpretar alternativas de uma alternação depois que ela casa com alguma delas. Então, se eu tiver três alternativas e a engine casar logo na primeira, as outras duas são ignoradas.

Caso a expressão regular falhe, a engine faz o backtracking para analisar ramificações que não foram testadas, pois talvez as outras também casem e façam a expressão regular inteira casar. Exemplo: limi(t|ta)do (casa com limitado. Note que, a princípio, a engine casa com a primeira alternativa da alternação. Só que, como o restante da expressão regular não casa, ela testa a segunda alternativa, que faz a expressão regular casar).

Quantificadores possessivos são muito parecidos com quantificadores gulosos. A diferença é que eles não fazem backtracking. Por isso, eles são chamados de possessivos. Os gulosos colaboram com a engine. Os possessivos não colaboram. Eles nunca cedem caracteres para a engine.

Quantificadores possessivos tem os mesmos tipos de quantificadores que os gulosos. A diferença é que cada quantificador tem um + no final dele: *+, ++, ?+ e {x,y}+. Exemplos: .*+o (não casa com nada, porque o quantificador casa com tudo e não faz backtracking), .*a*+o (casa com limitado, achado, lixeiro. Perceba que em todos esses exemplos o quantificador possessivo não casa com nada), (re|se)?+.*te (casa com repelente, serpente, reagente, sete).

Muitas vezes, usar um quantificador possessivo pode fazer com que expressões regulares falhem porque ele não faz o backtracking. Sendo assim, você pode pensar que não faz sentido usar esse quantificador. Pra que usá-lo se ele pode fazer a expressão falhar? Em alguns casos, pode valer a pena, porque ele tem um desempenho melhor. Como ele não permite o backtracking, a engine não perde o tempo dela com isso. Mas, como você pode ver, é um pouco mais complexo e menos natural formular expressões regulares com ele. Geralmente, não é bom usá-lo.