Expressões Regulares: Um Guia Prático para Desenvolvedores
· 12 min de leitura
Índice
- Fundamentos de Regex
- Classes de Caracteres e Quantificadores
- Grupos, Captura e Retrorreferências
- Asserções Lookahead e Lookbehind
- Padrões Comuns e Exemplos do Mundo Real
- Flags e Modificadores
- Otimização de Desempenho e Melhores Práticas
- Estratégias de Teste e Depuração
- Diferenças Específicas de Linguagem
- Técnicas Avançadas
- Principais Conclusões
- Perguntas Frequentes
Expressões regulares (regex) são uma das ferramentas mais poderosas no kit de ferramentas de um desenvolvedor. Elas fornecem uma maneira concisa e flexível de pesquisar, corresponder e manipular texto usando descrições de padrões. Seja validando entrada de usuário, analisando arquivos de log, extraindo dados de APIs ou realizando operações complexas de localizar e substituir, o conhecimento de regex é essencial para o desenvolvimento eficiente.
Este guia abrangente leva você dos fundamentos aos padrões avançados com exemplos práticos do mundo real. Ao final, você entenderá não apenas a sintaxe, mas quando e como aplicar regex efetivamente em seus projetos.
Fundamentos de Regex
Em sua essência, uma expressão regular é uma sequência de caracteres que define um padrão de busca. Pense nisso como uma mini-linguagem para descrever padrões de texto. Vamos começar com os blocos de construção essenciais que formam a base de cada padrão regex.
Caracteres Literais
O regex mais simples é uma string literal. O padrão hello corresponde ao texto exato "hello" na entrada. A maioria dos caracteres corresponde a si mesmos literalmente, tornando as buscas básicas diretas.
No entanto, certos caracteres têm significado especial em regex e são chamados de metacaracteres. Estes devem ser escapados com uma barra invertida quando você quer correspondê-los literalmente:
. ^ $ * + ? { } [ ] \ | ( )
Por exemplo, para corresponder a um ponto literal, use \. em vez de apenas .. Para corresponder a um cifrão, use \$.
Âncoras
Âncoras não correspondem a caracteres—elas correspondem a posições no texto. Elas são cruciais para correspondência precisa de padrões:
^— Corresponde ao início de uma linha ou string$— Corresponde ao final de uma linha ou string\b— Limite de palavra (entre um caractere de palavra e um caractere não-palavra)\B— Limite não-palavra (oposto de\b)\A— Início da string (em alguns sabores, difere de^no modo multilinha)\Z— Final da string (em alguns sabores, difere de$no modo multilinha)
Exemplo: O padrão ^Hello$ corresponde apenas a linhas contendo exatamente "Hello" sem nenhum outro texto antes ou depois.
Exemplo: O padrão \bcat\b corresponde a "cat" como uma palavra inteira, mas não ao "cat" em "category" ou "concatenate".
Dica profissional: Use âncoras para evitar correspondências parciais. Ao validar endereços de e-mail ou números de telefone, sempre ancore seus padrões com ^ e $ para garantir que toda a string corresponda ao seu padrão, não apenas uma parte dela.
Classes de Caracteres e Quantificadores
Classes de caracteres e quantificadores são onde o regex se torna verdadeiramente poderoso. Eles permitem que você corresponda a intervalos de caracteres e especifique quantas vezes um padrão deve se repetir.
Classes de Caracteres
Classes de caracteres correspondem a qualquer caractere de um conjunto definido. Elas são colocadas entre colchetes:
[abc]— Corresponde a a, b ou c[a-z]— Corresponde a qualquer letra minúscula[A-Z0-9]— Corresponde a qualquer letra maiúscula ou dígito[^abc]— Corresponde a qualquer caractere exceto a, b ou c (classe negada).— Corresponde a qualquer caractere exceto nova linha
Você pode combinar múltiplos intervalos: [a-zA-Z0-9] corresponde a qualquer caractere alfanumérico.
Classes de Caracteres Abreviadas
Essas classes predefinidas economizam tempo e melhoram a legibilidade:
| Abreviação | Equivalente | Descrição |
|---|---|---|
\d |
[0-9] |
Qualquer dígito |
\D |
[^0-9] |
Qualquer não-dígito |
\w |
[a-zA-Z0-9_] |
Qualquer caractere de palavra (letras, dígitos, sublinhado) |
\W |
[^a-zA-Z0-9_] |
Qualquer caractere não-palavra |
\s |
[ \t\n\r\f\v] |
Qualquer caractere de espaço em branco |
\S |
[^ \t\n\r\f\v] |
Qualquer caractere não-espaço em branco |
Quantificadores
Quantificadores especificam quantas vezes o elemento anterior deve corresponder:
*— Zero ou mais vezes (ganancioso)+— Uma ou mais vezes (ganancioso)?— Zero ou uma vez (opcional){n}— Exatamente n vezes{n,}— Pelo menos n vezes{n,m}— Entre n e m vezes (inclusive)
Exemplo: \d{3}-\d{2}-\d{4} corresponde a um formato de Número de Seguro Social como "123-45-6789".
Exemplo: colou?r corresponde tanto a "color" quanto a "colour" (o 'u' é opcional).
Quantificadores Gananciosos vs. Preguiçosos
Por padrão, os quantificadores são gananciosos—eles correspondem ao máximo de texto possível. Adicionar ? após um quantificador o torna preguiçoso (não-ganancioso), correspondendo ao mínimo possível:
*?— Zero ou mais vezes (preguiçoso)+?— Uma ou mais vezes (preguiçoso)??— Zero ou uma vez (preguiçoso){n,m}?— Entre n e m vezes (preguiçoso)
Exemplo: Dado o texto <div>content</div>, o padrão <.+> (ganancioso) corresponde à string inteira, enquanto <.+?> (preguiçoso) corresponde apenas a <div>.
Dica rápida: Ao extrair conteúdo entre delimitadores (como tags HTML ou aspas), sempre use quantificadores preguiçosos para evitar corresponder demais. O padrão ".*?" extrai corretamente strings entre aspas, enquanto ".*" corresponderia da primeira aspa até a última aspa em toda a linha.
Grupos, Captura e Retrorreferências
Grupos permitem que você trate múltiplos caracteres como uma única unidade e capture texto correspondido para uso posterior. Eles são essenciais para padrões complexos e extração de texto.
Grupos de Captura
Parênteses () criam um grupo de captura. O texto correspondido é armazenado e pode ser referenciado posteriormente:
(\d{3})-(\d{3})-(\d{4})
Este padrão corresponde a um número de telefone e captura três grupos: código de área, prefixo e número da linha. Na maioria das linguagens, você pode acessar essas capturas como $1, $2, $3 ou sintaxe similar.
Grupos Não-Capturadores
Às vezes você precisa de agrupamento para quantificadores ou alternância, mas não precisa capturar o texto. Use (?:...) para grupos não-capturadores:
(?:https?|ftp)://[^\s]+
Isso corresponde a URLs começando com http, https ou ftp sem capturar o protocolo separadamente. Grupos não-capturadores são mais eficientes quando você não precisa do texto capturado.
Grupos de Captura Nomeados
Grupos nomeados tornam seu regex mais legível e sustentável. A sintaxe varia por linguagem:
- Python, .NET, PCRE:
(?P<name>...)ou(?<name>...) - JavaScript (ES2018+):
(?<name>...)
Exemplo:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
Isso corresponde a datas e cria capturas nomeadas para ano, mês e dia, tornando seu código mais autodocumentado.
Retrorreferências
Retrorreferências permitem que você corresponda ao mesmo texto que foi capturado anteriormente no padrão:
\1,\2, etc. — Referenciam grupos capturados por número\k<name>— Referenciam grupos nomeados (sintaxe varia)
Exemplo: \b(\w+)\s+\1\b corresponde a palavras repetidas como "the the" ou "is is".
Exemplo: (['"])(.*?)\1 corresponde a strings entre aspas simples e duplas, garantindo que a aspa de fechamento corresponda à aspa de abertura.
Alternância
O caractere pipe | atua como um operador OU. É frequentemente usado com grupos:
(cat|dog|bird)
Isso corresponde a "cat", "dog" ou "bird". Tenha cuidado com a ordem de alternância—o motor regex tenta alternativas da esquerda para a direita e para na primeira correspondência.
Asserções Lookahead e Lookbehind
Asserções lookaround são asserções de largura zero que correspondem a uma posição com base no que vem antes ou depois, sem incluir esse texto na correspondência. Elas são incrivelmente poderosas para cenários de correspondência complexos.
Asserções Lookahead
Lookahead verifica o que vem após a posição atual:
(?=...)— Lookahead positivo (deve ser seguido por...)(?!...)— Lookahead negativo (NÃO deve ser seguido por...)
Exemplo: \d+(?= dollars) corresponde a números seguidos por " dollars", mas não inclui " dollars" na correspondência.
Exemplo: ^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$ valida senhas que contêm pelo menos uma letra maiúscula, uma letra minúscula, um dígito e têm pelo menos 8 caracteres.
Asserções Lookbehind
Lookbehind verifica o que vem antes da posição atual:
(?<=...)— Lookbehind positivo (deve ser precedido por...)(?<!...)— Lookbehind negativo (NÃO deve ser precedido por...)
Exemplo: (?<=\$)\d+ corresponde a números precedidos por um cifrão, mas não inclui o cifrão na correspondência.
Exemplo: (?<!un)happy corresponde a "happy", mas não a "unhappy".
Dica profissional: Asserções lookaround são perfeitas para cenários de validação onde você precisa verificar múltiplas condições sem consumir caracteres. Elas também são essenciais quando você precisa corresponder algo com base no contexto, mas só quer extrair uma parte específica.
Exemplos Práticos de Lookaround
Extrair domínio de e-mail sem o símbolo @:
(?<=@)[a-zA-Z0-9.-]+
Corresponder palavras não seguidas por vírgula:
\b\w+\b(?!,)
Encontrar números não precedidos por sinal de menos (apenas números positivos):
(?<!-)\b\d+\b
Padrões Comuns e Exemplos do Mundo Real
Vamos explorar padrões regex testados em batalha para tarefas comuns de desenvolvimento. Esses padrões estão prontos para produção e lidam com casos extremos que você encontrará em aplicações reais.
Validação de E-mail
Um padrão de e-mail prático que equilibra rigor com uso no mundo real:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Este padrão permite formatos comuns de e-mail enquanto previne erros óbvios. Para validação compatível com RFC, considere usar uma biblioteca dedicada—o regex completo RFC 5322 tem mais de 6.000 caracteres.
Correspondência de URL
Corresponder URLs HTTP/HTTPS com www opcional:
https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)
Para uma versão mais simples que captura a maioria das URLs:
https?://[^\s]+
Números de Telefone
Números de telefone dos EUA com formatação flexível:
^(\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$
Isso corresponde a formatos como:
- 123-456-7890
- (123) 456-7890
- +1 123 456 7890
- 1234567890
Formatos de Data
Formato de data ISO 8601 (AAAA-MM-DD):
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
Formato de data dos EUA (MM/DD/AAAA):
^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$
Endereços IP
Validação de endereço IPv4:
^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$
Isso garante que cada octeto esteja entre 0 e 255.
Números de Cartão de Crédito
Formato básico de cartão de crédito (com espaços ou traços opcionais):
^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$
Lembre-se de usar o algoritmo de Luhn para validação real—regex apenas verifica o formato.
Cores Hexadecimais
Corresponder códigos de cor hex com prefixo # opcional:
^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$
Isso corresponde tanto a formatos de 6 dígitos (#FF5733) quanto de 3 dígitos (#F57).
Validação de Nome de Usuário
Nomes de usuário alfanuméricos com sublinhados e hífens, 3-16 caracteres:
^[a-zA-Z0-9_-]{3,16}$
Força de Senha
Requer pelo menos 8 caracteres, uma maiúscula, uma minúscula, um dígito e um caractere especial:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&