Expressões regulares: classes, quantificadores e grupos

Atualizado:

Uma expressão regular, ou regex, é um pequeno padrão que descreve um texto: “quatro dígitos, um hífen, dois dígitos”, ou “uma palavra que começa com letra maiúscula”. Os programas usam regex para buscar, para conferir o que o usuário digitou e para extrair pedaços de uma linha. Este guia explica as peças de um padrão, com exemplos para colar no testador de regex, e depois as armadilhas: padrões que encontram mais do que deviam, padrões que podem não terminar nunca e as diferenças entre os motores de JavaScript, Python e PHP. Os exemplos usam a sintaxe do JavaScript, a mesma do testador e de todos os navegadores.

Caracteres que significam outra coisa

A maioria dos caracteres de um padrão representa a si mesma: sol encontra as letras s, o e l nessa ordem. Quatorze não, porque têm uma função no padrão: . ^ $ * + ? ( ) [ ] { } | \ e, dentro do código JavaScript, a barra que fecha o padrão. Para buscar um deles literalmente, coloque uma barra invertida antes.

Classes de caracteres

Uma classe encontra um caractere de um conjunto. Os colchetes listam o conjunto; uma barra invertida com uma letra dá um conjunto pronto; a letra maiúscula significa o contrário.

PadrãoEncontra um…
[aeiou]vogal sem acento: a, e, i, o ou u
[^aeiou]caractere que não seja nenhum desses, incluindo espaços e dígitos
[a-z0-9]letra minúscula de a a z, ou um dígito
\ddígito de 0 a 9 (\D: qualquer outro)
\wletra de A a Z ou de a a z, dígito ou sublinhado (\W: qualquer outro)
\sespaço, tabulação, quebra de linha ou outro espaço em branco (\S: qualquer outro)
.caractere exceto quebra de linha (qualquer um com a flag s)
\p{L}letra de qualquer alfabeto, com a flag u ou v

No JavaScript, \d e \w só conhecem o alfabeto latino básico: \w+ quebra São em S e o, e \d não encontra o dígito arábico oriental ٣. Com a flag u, \p{L}+ encontra São inteiro e \p{Nd} encontra dígitos de qualquer escrita. O Python 3 faz o contrário: em texto comum, o \d e o \w dele já cobrem Unicode, a não ser com a flag ASCII. O motor PCRE2 do PHP fica no ASCII enquanto as propriedades Unicode não forem ligadas, por exemplo com (*UCP) no começo do padrão.

Quantificadores: quantas vezes

Um quantificador diz quantas vezes o elemento antes dele pode se repetir. Ele vale para um caractere, uma classe ou um grupo entre parênteses.

PadrãoSignifica
a*zero ou mais
a+um ou mais
a?zero ou um, ou seja, opcional
a{3}exatamente três
a{3,}três ou mais
a{2,4}de dois a quatro

Os quantificadores são gulosos: pegam tudo o que podem e só devolvem o que o resto do padrão precisa. Em <b>negrito</b>, o padrão <.+> encontra a string inteira, do primeiro < ao último >. Um ponto de interrogação depois deixa o quantificador preguiçoso, que pega o mínimo: <.+?> encontra <b> e depois </b>. colou?r encontra as duas grafias inglesas, color e colour, e \d{3,} encontra números de três dígitos ou mais.

Âncoras e limites de palavra

Âncoras encontram uma posição, não um caractere. ^ é o começo do texto e $ o fim; com a flag m, viram o começo e o fim de cada linha. \b é um limite de palavra, o ponto entre um caractere de palavra e qualquer outra coisa, então \bsol\b encontra sol como palavra, mas não dentro de solar. Sem âncoras, um padrão usado para validar também aceita texto com caracteres a mais em volta da parte que bate: \d{4} encontra quatro dígitos dentro de abc12345, enquanto ^\d{4}$ só aceita exatamente quatro dígitos.

Grupos, alternativas e retrovisores

Os parênteses agrupam parte de um padrão para que um quantificador ou uma alternativa valha para o grupo todo, e capturam o texto encontrado para que um programa possa lê-lo: (\d{4})-(\d{2})-(\d{2}) captura ano, mês e dia separados. (?:…) agrupa sem capturar, e (?<ano>\d{4}) dá nome à captura.

A barra vertical significa “ou” e tem a menor precedência de todas: ^sol|mar$ significa “sol no começo” ou “mar no fim”, então encontra sol em solar e mar em amar. Para dizer “o texto inteiro é sol ou mar”, agrupe as alternativas: ^(?:sol|mar)$.

Um retrovisor encontra o mesmo texto que um grupo já capturou: (\w)\1 encontra uma letra seguida dela mesma, rr e ss em “carro e passarinho”, e \k<nome> faz o mesmo com um grupo nomeado.

Lookahead e lookbehind

Um lookaround confere o que vem antes ou depois de uma posição sem incluir isso no resultado. (?=…) exige que algo venha depois, (?!…) proíbe; (?<=…) exige que algo venha antes, (?<!…) proíbe. Servem para pegar um número pela unidade ou pela moeda, ou para juntar várias condições sobre o mesmo texto.

Flags

As flags mudam como o padrão inteiro é aplicado. No JavaScript, elas vêm depois da barra de fechamento, como em /sol/gi; no testador, elas têm um campo próprio.

FlagEfeito
gencontrar todas as ocorrências, não só a primeira
iignorar a diferença entre maiúsculas e minúsculas
m^ e $ valem para cada linha
so ponto também encontra quebras de linha
umodo Unicode: \p{…}, e um emoji conta como um caractere
vmodo Unicode com operações de conjunto nas classes; use no lugar de u
ygrudenta (sticky): buscar só onde a ocorrência anterior terminou
dregistrar onde cada grupo começa e termina

Validar e-mails, datas e outros formatos

Uma regex consegue conferir a forma de um dado, não se ele é real. O padrão HTML define o que um <input type="email"> aceita com um padrão próprio, e diz abertamente que se afasta de propósito da RFC 5322, a norma do formato de e-mail, que permite formas como nomes entre aspas com espaços que quase ninguém usa. Ele aceita ana@example.com e também ana@localhost; recusa ana@my_domain.example, porque um nome de domínio não pode ter sublinhado. Se a caixa existe, só uma mensagem diz.

Com datas é parecido: ^\d{4}-\d{2}-\d{2}$ aceita 2026-02-31, que não existe. Confira a forma com o padrão e deixe uma função de datas decidir se a data é válida. E não analise HTML nem JSON com expressões regulares: estruturas aninhadas precisam de um parser.

Quando um padrão não termina nunca

A maioria dos motores, incluindo os de JavaScript, Python e PHP, funciona por retrocesso (backtracking): quando um caminho falha, volta e tenta outra forma de dividir o texto entre as partes do padrão. Um grupo que repete algo que também se repete, como ^(a+)+$, pode ser dividido num número de formas que dobra a cada caractere a mais. Numa sequência de letras a terminada em ponto de exclamação o padrão nunca pode bater, mas o motor testa todas as divisões antes de desistir. A OWASP chama isso de negação de serviço por expressões regulares, ReDoS, e cita padrões como (a+)+$, ([a-zA-Z]+)*$ e (a|aa)+$.

A solução é tirar a ambiguidade: ^a+$ descreve o mesmo texto e falha na hora. Evite quantificadores aninhados e alternativas que possam encontrar os mesmos caracteres, e nunca execute um padrão vindo de um usuário sem limite de tempo. O testador de regex roda cada busca num worker separado e a interrompe depois de meio segundo, então um padrão desses é avisado em vez de travar a página.

Testador de expressões regulares

Nem todo motor é igual

O básico acima funciona em quase todo lugar, mas os detalhes mudam de uma linguagem para outra. Um padrão escrito para um motor deve ser testado no outro antes de você confiar nele.

RecursoJavaScriptPython (re)PHP (PCRE2)
Grupo nomeado(?<nome>…)(?P<nome>…)as duas formas
\d e \wsó ASCIIUnicode por padrãoASCII, a não ser com UCP
Quantificadores possessivos e grupos atômicos (a++, (?>…))nãosim, desde o Python 3.11sim
Flags embutidas como (?i)só a forma delimitada (?i:…), desde o ECMAScript 2025simsim

O lookbehind também muda: o JavaScript aceita um de tamanho variável, como (?<=[a-z]+), enquanto o Python exige largura fixa e o recusa. O Python também escreve as barras invertidas de outro jeito no código: uma string crua, r"\d+", mantém as barras como foram digitadas, enquanto os padrões JavaScript entre barras não precisam dobrá-las. Numa string JavaScript passada para new RegExp(), cada barra invertida precisa ser escrita duas vezes.

Perguntas frequentes

Por que meu padrão só encontra uma ocorrência?

No JavaScript, a busca para na primeira ocorrência se a flag g não estiver ligada. No testador, acrescente g às flags.

Por que o \w não encontra letras acentuadas nem o ç?

Porque no JavaScript o \w significa só de A a Z, de a a z, dígitos e sublinhado. Use \p{L} com a flag u para letras de qualquer alfabeto.

Como encontro um ponto, um parêntese ou um ponto de interrogação?

Coloque uma barra invertida antes: \. \( \? e assim por diante. Dentro de colchetes a maioria perde o significado, então [.?] encontra um ponto ou um ponto de interrogação.

Uma expressão regular consegue validar um e-mail?

Só a forma dele. O padrão do HTML é uma boa escolha para formulários; se o endereço recebe e-mail, só dá para saber enviando uma mensagem.

Por que meu padrão travou o programa?

Provavelmente ele repete um grupo que também se repete, como (a+)+, e o texto quase bate. Reescreva sem quantificadores aninhados e rode padrões de usuários com limite de tempo.

Referências

  1. MDN Web Docs — Regular expressions (JavaScript guide)
  2. MDN Web Docs — Regular expression syntax cheat sheet
  3. ECMAScript® Language Specification — RegExp (Regular Expression) Objects
  4. TC39 — Finished proposals (RegExp modifiers and duplicate named groups: ECMAScript 2025)
  5. Python documentation — re: regular expression operations
  6. PCRE2 — pcre2pattern: syntax and semantics of the regular expressions
  7. OWASP — Regular expression Denial of Service (ReDoS)
  8. WHATWG HTML Standard — Valid email address
  9. RFC 5322 — Internet Message Format (October 2008)

Guias relacionados