Cheat Sheet de Regex: metacaracteres, grupos e lookarounds (referência completa)
Uma expressão regular é uma pequena linguagem de padrões para casar texto. \d+ significa “um ou mais dígitos”, ^Error significa “uma linha que começa com Error”. É só isso o trabalho dela. Esta cheat sheet de regex entrega a sintaxe em uma única página rolável: metacaracteres, quantificadores, âncoras, grupos, lookarounds e flags, além de 15+ padrões que você pode colar em JavaScript ou Python hoje mesmo.
É uma referência para quem já sabe o que é uma string, não um tour. Pule direto para a Tabela de Referência Rápida se só precisa dos símbolos. Leia as seções de lookaround e armadilhas se algum dia uma regex sua já travou um servidor.
1. O que é regex e por que você ainda precisa dela em 2026
Uma regex é um padrão compilado em uma máquina de estados que varre uma string e ou casa ou falha. A gramática é pequena, os casos de uso não são.
A IA pode rascunhar um padrão para você, mas algumas tarefas ainda pertencem a um humano escrevendo regex à mão:
- Parsing de logs: você tem dez milhões de linhas de logs de acesso do
nginxe precisa de toda requisição 5xx vinda de um user agent específico. Uma regex de 40 caracteres por cima degrep -Eroda em segundos; uma chamada de LLM por linha, não. - Validação de formulários e campos: números de telefone, CEPs, timestamps ISO, chaves de licença. O padrão fica ao lado do input e executa a cada tecla pressionada no navegador.
- Find-and-replace em massa: refatorando mil arquivos onde você precisa capturar um nome e reinjetá-lo.
sed,ripgrepe o “Replace in files” do seu editor falam regex nativamente.
Para a metade JSON da mesma caixa de ferramentas, veja nosso guia rápido do jq na linha de comando.
1.1 Como ler um padrão de regex (tutorial de expressão regular em 5 segundos)
A maioria dos padrões fica mais fácil de ler da esquerda para a direita, um token de cada vez. Pegue ^[A-Z]\w+\d{2,4}$ como exemplo:
^ancora o match no início da string.[A-Z]casa com exatamente uma letra maiúscula.\w+casa com um ou mais caracteres de palavra.\d{2,4}casa com entre dois e quatro dígitos.$ancora no fim da string.
O truque é ler primeiro as âncoras, depois as classes de caracteres, depois os quantificadores e, por último, os limites.
2. Tabela de Referência Rápida
É essa a seção pela qual a maioria veio. Copie o que precisar.
Metacaracteres
| Padrão | Casa com |
|---|---|
. | Qualquer caractere exceto nova linha (ou qualquer caractere com a flag s/dotall) |
\d | Um dígito ([0-9], ou todos os dígitos Unicode com a flag u) |
\D | Um não-dígito |
\w | Um caractere de palavra ([A-Za-z0-9_]) |
\W | Um caractere que não é de palavra |
\s | Qualquer espaço em branco (espaço, tab, nova linha, …) |
\S | Qualquer caractere que não seja espaço em branco |
Quantificadores
| Padrão | Casa com |
|---|---|
* | 0 ou mais (guloso) |
+ | 1 ou mais (guloso) |
? | 0 ou 1 (guloso) |
{n} | Exatamente n vezes |
{n,m} | Entre n e m vezes |
{n,} | n ou mais vezes |
*?, +?, ??, {n,m}? | Versões preguiçosas de cada quantificador |
Âncoras
| Padrão | Casa com |
|---|---|
^ | Início da string (ou início de linha com a flag m) |
$ | Fim da string (ou fim de linha com a flag m) |
\b | Fronteira de palavra |
\B | Não-fronteira de palavra |
\A | Início absoluto da string (Python) |
\Z | Fim absoluto da string (Python) |
Classes de caracteres
| Padrão | Casa com |
|---|---|
[abc] | Qualquer um entre a, b, c |
[^abc] | Qualquer coisa exceto a, b, c |
[a-z] | Qualquer letra minúscula |
[0-9] | Qualquer dígito |
\p{L} | Qualquer letra Unicode (flag u em JS, padrão no re do Python) |
Grupos
| Padrão | Casa com |
|---|---|
(...) | Grupo de captura |
(?:...) | Grupo sem captura |
(?<name>...) | Captura nomeada (JS ES2018+); Python usa (?P<name>...) |
\1, \2 | Referência de volta ao grupo 1, 2 |
Lookaround
| Padrão | Casa com |
|---|---|
(?=...) | Lookahead positivo |
(?!...) | Lookahead negativo |
(?<=...) | Lookbehind positivo |
(?<!...) | Lookbehind negativo |
Flags
| Flag | Efeito |
|---|---|
i | Sem distinção de maiúsculas/minúsculas |
m | Multiline: ^ e $ casam por linha |
s | Dotall: . casa com novas linhas |
g | Global (JS) — encontra todos os matches |
u | Modo Unicode |
y | Sticky (JS) — ancora em lastIndex |
3. Metacaracteres e classes de caracteres
3.1 Literais vs caracteres especiais
A maioria dos caracteres é literal. Os 12 metacaracteres que precisam ser escapados quando você os quer como eles mesmos são:
. ^ $ * + ? ( ) [ ] { } | \
Esquecer de escapar . é o bug de regex mais comum que existe. \. casa com um ponto literal. Dentro de uma classe de caracteres, [.] também casa com um ponto literal: a maioria dos metacaracteres perde o poder dentro de [...], exceto ], \, ^ (quando vem primeiro) e - (no meio).
3.2 Atalhos de caracteres
As classes-atalho parecem simples até Unicode aparecer:
// JavaScript — sem a flag u, \d é só ASCII
/\d/.test('5'); // true
/\d/.test('٥'); // false (dígito árabe-índico)
/\d/u.test('٥'); // false — mesmo com u, \d continua ASCII em JS
/\p{N}/u.test('٥'); // true — \p{N} é a classe de dígito ciente de Unicode
# Python — o módulo re trata \d como Unicode por padrão
import re
re.match(r'\d', '٥') # <Match span=(0, 1)>
re.match(r'(?a)\d', '٥') # None — (?a) força ASCII
Se você só lida com entrada ASCII em inglês, \d e [0-9] são intercambiáveis. No momento em que um usuário cola um nome com acento, você vai querer \p{L} no lugar de \w.
3.3 Classes de caracteres customizadas
// JavaScript
/[A-Za-z][A-Za-z0-9_-]{2,29}/.test('valid_handle-1'); // true
// Negação e intervalos combinados
/[^aeiou\s]/g // qualquer caractere que não seja vogal nem espaço em branco
Para categorias Unicode, \p{L} é “qualquer letra”, \p{N} é “qualquer número”, \p{Script=Han} é “qualquer caractere Han”. JavaScript exige a flag u; Python suporta \p{...} apenas via o pacote regex no PyPI, não no re da stdlib.
Se você trabalha na linha de comando, também pode encontrar as classes de caracteres POSIX:
| Classe POSIX | Casa com | Equivalente ASCII |
|---|---|---|
[[:alpha:]] | letras | [A-Za-z] |
[[:digit:]] | dígitos | [0-9] (\d) |
[[:alnum:]] | letras + dígitos | [A-Za-z0-9] |
[[:space:]] | espaços em branco | \s |
[[:upper:]] | maiúsculas | [A-Z] |
[[:lower:]] | minúsculas | [a-z] |
As classes POSIX funcionam em grep -E e sed -E. Elas não funcionam em JavaScript nem no re do Python — use \d, \s, \w no lugar.
4. Quantificadores: guloso vs preguiçoso
4.1 Quantificadores básicos
/a*/.exec('aaab') // ['aaa'] — 0 ou mais
/a+/.exec('aaab') // ['aaa'] — 1 ou mais
/a?/.exec('aaab') // ['a'] — 0 ou 1
/a{2,3}/.exec('aaaab') // ['aaa'] — 2 a 3
4.2 Guloso vs preguiçoso
Por padrão, quantificadores são gulosos: eles agarram tudo que podem e depois recuam para fazer o padrão inteiro caber. Adicione ? para deixá-los preguiçosos.
const html = '<p>one</p><p>two</p>';
html.match(/<p>.*<\/p>/)[0]; // '<p>one</p><p>two</p>' (guloso devora os dois)
html.match(/<p>.*?<\/p>/)[0]; // '<p>one</p>' (preguiçoso para no primeiro)
A versão preguiçosa é quase sempre o que você quer ao extrair tags ou strings entre aspas. Melhor ainda: evite . por completo e use uma classe negada. <p>[^<]*</p> é mais rápido que <p>.*?</p> porque não há nada em que fazer backtracking.
4.3 Backtracking catastrófico
É assim que regex trava um servidor. Aninhe um quantificador dentro de outro com sobreposição ambígua, e o engine explora um número exponencial de caminhos antes de desistir.
// Não faça isso
/(a+)+b/.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!'); // leva segundos
Para 41 as seguidos de !, o engine tenta cerca de 2^41 pontos de divisão antes de decidir que o b está faltando. Três correções:
- Achate o padrão:
/a+b/faz o mesmo trabalho sem aninhamento. - Use um grupo atômico (Python
regex, PCRE, Java, Ruby):(?>a+)+b. Uma vez quea+casa, o engine se recusa a fazer backtracking nele. - Troque de engine: o
regexpdo Go, o RE2 e a crateregexdo Rust usam um NFA de tempo linear e não conseguem fazer backtracking catastrófico por design.
JavaScript e o re do Python ambos fazem backtracking e não têm grupos atômicos na stdlib (o pacote regex no PyPI adiciona em Python). Quando você controla o tamanho da entrada, tudo bem. Quando a entrada vem de um usuário, valide o tamanho primeiro ou pré-compile com RE2.
5. Âncoras e fronteiras de palavra
5.1 ^ e $
Por padrão, ^ é o início da entrada inteira e $ é o fim. Com a flag m (multiline), eles passam a ser o início e o fim de cada linha.
const log = 'INFO start\nERROR boom\nINFO done';
log.match(/^ERROR.*/); // null — modo single-line, ^ só casa no índice 0
log.match(/^ERROR.*/m); // ['ERROR boom']
5.2 \b e \B
\b é uma asserção de largura zero: casa com a posição entre um caractere de palavra (\w) e um que não é de palavra. Útil para busca de palavra inteira:
/\bcat\b/.test('the cat sat'); // true
/\bcat\b/.test('concatenate'); // false
Fronteiras de palavra são definidas em cima de \w, que é ASCII por padrão. Textos em chinês, japonês e coreano não têm espaços entre as palavras, então \b não detecta as bordas das palavras nesses casos. Você precisa de um tokenizer (jieba, MeCab) antes da regex, não no lugar dela.
5.3 Modo multiline
import re
text = "INFO ok\nERROR fail\nINFO done\n"
re.findall(r'^ERROR.*$', text) # []
re.findall(r'^ERROR.*$', text, re.MULTILINE) # ['ERROR fail']
Em JavaScript a mesma coisa fica text.match(/^ERROR.*$/gm). Combine m com g para pegar cada linha que casa.
6. Grupos, captura e backreferences
6.1 Grupos de captura
Parênteses fazem dois trabalhos: agrupam subpadrões para quantificadores e capturam o match para uso posterior.
'2026-05-13'.match(/(\d{4})-(\d{2})-(\d{2})/);
// ['2026-05-13', '2026', '05', '13', index: 0, ...]
Grupos são numerados da esquerda para a direita pelo seu parêntese de abertura, começando em 1.
6.2 Grupos sem captura
Quando você só precisa agrupar, sem capturar, use (?:...). É mais rápido e mantém os grupos numerados organizados:
/(?:https?):\/\/(\S+)/.exec('see https://go-tools.org');
// ['https://go-tools.org', 'go-tools.org']
// — o protocolo é agrupado mas não capturado; o grupo 1 é o host
6.3 Grupos nomeados
Nomear grupos torna os padrões legíveis e seguros para refatorar.
// JavaScript (ES2018+)
const m = '2026-05-13'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
m.groups.year; // '2026'
# Python — note a sintaxe (?P<...>)
import re
m = re.match(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', '2026-05-13')
m.group('year') # '2026'
6.4 Backreferences
Backreferences permitem que uma parte posterior do padrão repita o que uma captura anterior casou.
// Encontra qualquer caractere que se repete consecutivamente
'bookkeeper'.match(/(\w)\1/g); // ['oo', 'kk', 'ee']
// Casa tags HTML pareadas pelo nome
const tag = /<(\w+)>(.*?)<\/\1>/;
'<b>bold</b>'.match(tag);
// ['<b>bold</b>', 'b', 'bold']
Em Python, \1 funciona tanto no padrão quanto na substituição; referências nomeadas se escrevem (?P=name) no padrão e \g<name> nas substituições de re.sub.
7. Lookarounds: lookahead e lookbehind
Lookarounds são asserções de largura zero. Eles verificam uma condição sem consumir caracteres, então você pode encadeá-los.
7.1 Lookahead
// Senha: pelo menos 8 caracteres, um dígito, uma maiúscula, uma minúscula
const strong = /^(?=.*\d)(?=.*[A-Z])(?=.*[a-z]).{8,}$/;
strong.test('Hunter2!'); // true
strong.test('hunter2!'); // false — sem maiúscula
// Lookahead negativo — nomes de arquivo que não são .tmp
/^[\w-]+(?!\.tmp$)\.[a-z]+$/.test('report.csv'); // true
7.2 Lookbehind
Lookbehind é a imagem espelhada: ele afirma o que vem antes da posição atual.
// Extrai um preço depois de um símbolo de moeda — fica com o número, descarta o $
'price: $42.50'.match(/(?<=\$)\d+(\.\d+)?/); // ['42.50', '.50']
// Lookbehind negativo — casa Bond, mas não James Bond
'Mr. Bond'.match(/(?<!James )Bond/); // ['Bond']
'James Bond'.match(/(?<!James )Bond/); // null
7.3 Lookbehind em JavaScript vs Python
Este é um dos poucos pontos em que os dois engines divergem o suficiente para quebrar um padrão na hora de portar.
| Engine | Tamanho do lookbehind |
|---|---|
| JavaScript (V8, SpiderMonkey, JSC 16.4+) | Largura variável desde ES2018. (?<=\d+) é válido. |
re da stdlib do Python | Apenas largura fixa. (?<=\d+) lança error: look-behind requires fixed-width pattern. |
Pacote regex no PyPI do Python | Largura variável suportada. import regex; regex.search(r'(?<=\d+)abc', '12abc'). |
Contorno em Python: reescreva o lookbehind com uma repetição conhecida ((?<=\d{3})) ou capture o prefixo e corte-o depois de casar.
8. Flags e modificadores
8.1 i — sem distinção de maiúsculas/minúsculas
/error/i.test('FATAL ERROR'); // true
re.search(r'error', 'FATAL ERROR', re.IGNORECASE) # <Match span=(6, 11)>
8.2 m e s
m transforma ^ e $ em âncoras por linha. s (dotall) faz . casar com novas linhas. São independentes; combine-as quando quiser as duas.
/<script>(.*?)<\/script>/s.exec('<script>\nalert(1)\n</script>')[1];
// '\nalert(1)\n' — sem s, o . recusaria as novas linhas
8.3 g — global
Em JavaScript, g muda a API, não o próprio casamento. Sem g, String.match devolve os grupos de captura; com g, devolve cada string que casou. Use matchAll para preservar grupos de captura em todos os matches.
const text = 'a=1 b=2 c=3';
text.match(/(\w)=(\d)/); // primeiro match com grupos
text.match(/(\w)=(\d)/g); // ['a=1', 'b=2', 'c=3'] — sem grupos
[...text.matchAll(/(\w)=(\d)/g)]; // cada match, com grupos
Python não usa g: re.findall, re.finditer e re.sub são as variantes globais.
8.4 u — Unicode e \p{...}
// Casa qualquer caractere Han (chinês, kanji japonês)
/\p{Script=Han}+/gu.test('Hello 世界'); // true
// Casa emoji (extended pictographic)
/\p{Extended_Pictographic}/u.test('👋'); // true
Em Python, Unicode está ligado por padrão; re.findall(r'[一-鿿]+', text) é o equivalente para o intervalo Han. Para escapes completos de propriedades Unicode, use o pacote regex do PyPI: regex.findall(r'\p{Script=Han}+', text).
9. Padrões comuns que você vai usar todo dia
9.1 Validação de e-mail
Seja honesto sobre qual versão você precisa.
// O padrão dos 95% — o que a maioria dos validadores de formulário usa
const email = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
email.test('a@b.co'); // true
// O padrão "quero ser fiel à RFC 5322"
const rfc = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
A verdade: validação completa de e-mail RFC 5322 em regex pura tem ~6000 caracteres e ainda erra em casos de borda. Use o padrão dos 95% e depois mande um e-mail de verificação. É o único teste que funciona de verdade.
9.2 Extração de URL
const urlPattern = /https?:\/\/[^\s<>"]+/g;
const found = 'See https://example.com/a?b=1 and http://x.io'.match(urlPattern);
// ['https://example.com/a?b=1', 'http://x.io']
Depois de extrair uma URL, normalmente você quer inspecionar a query string. Cole-a no nosso Decodificador e Codificador de URL e dá para ler parâmetros com percent-encoding num piscar de olhos. Para o quadro completo de quando codificar versus decodificar, leia o guia de codificação e decodificação de URL.
9.3 Números de telefone
// E.164 — internacional, + opcional e código de país de 1-3 dígitos
const e164 = /^\+?[1-9]\d{1,14}$/;
e164.test('+14155551234'); // true
// Plano de numeração da América do Norte com separadores
const nanp = /^(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
nanp.test('(415) 555-1234'); // true
Para qualquer coisa além de “este formato é plausível?”, use libphonenumber. Regex não consegue validar que um código de área existe de fato.
9.4 IPv4 e IPv6
// IPv4 — estrito, 0-255 por octeto
const ipv4 = /^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$/;
ipv4.test('192.168.1.1'); // true
ipv4.test('999.0.0.1'); // false
// IPv6 — a forma simplificada. O padrão completo da RFC 4291 tem ~600 caracteres.
const ipv6simple = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
ipv6simple.test('2001:0db8:85a3:0000:0000:8a2e:0370:7334'); // true
Para IPv6 real com a forma abreviada ::, IPv4 embutido e identificadores de zona, use isIP() de node:net ou ipaddress.ip_address() do Python. Tentar fazer isso em regex pura é um ritual de passagem que depois vira fardo de manutenção.
9.5 Datas e timestamps ISO 8601
// Apenas data — YYYY-MM-DD
const isoDate = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
isoDate.test('2026-05-13'); // true
// Data + hora + segundos fracionários opcionais + Z ou offset
const iso = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
iso.test('2026-05-13T09:30:00.123Z'); // true
ISO 8601 parece simples e está cheia de armadilhas: segundos bissextos, datas com semana (2026-W19), datas ordinais (2026-133). Para segundos versus milissegundos da época e mudanças de fuso horário, veja o Guia de Unix Timestamp: Fuso Horário e Horário de Verão.
10. Fluxos de find/replace com regex
10.1 JavaScript — String.replace com $1
// Reformatar datas dos EUA: MM/DD/YYYY -> YYYY-MM-DD
'05/13/2026'.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$1-$2');
// '2026-05-13'
// Use um callback quando a substituição é condicional
'price 42 dollars'.replace(/(\d+) dollars/, (_, n) => `$${n}`);
// 'price $42'
$1, $2, … referenciam grupos numerados. $<name> referencia grupos nomeados. $& é o match completo; $$ é um $ literal.
10.2 Python — re.sub com \1 e callbacks
import re
# A mesma reformatação de data acima
re.sub(r'(\d{2})/(\d{2})/(\d{4})', r'\3-\1-\2', '05/13/2026')
# '2026-05-13'
# Callback — coloca em maiúsculas todo endereço de e-mail em uma string
def upper_email(m):
return m.group(0).upper()
re.sub(r'[\w.-]+@[\w.-]+', upper_email, 'mail me at hi@go-tools.org')
# 'mail me at HI@GO-TOOLS.ORG'
Nas substituições, Python usa \1 ou \g<name>. O prefixo de raw string r'...' importa: sem ele, \1 vira um caractere literal.
10.3 CLI: sed, grep, ripgrep, jq
Para refatorações em lote na linha de comando, regex sai do script e vai para o shell:
# ripgrep — encontra todo TODO com um nome anexado
rg -n '\bTODO\(([^)]+)\)' --replace 'TODO(\1)'
# grep -E com âncoras — linhas de login com falha em auth.log
grep -E '^[A-Z][a-z]{2} +[0-9]+ .*Failed password' /var/log/auth.log
# sed — remove espaços em branco no fim, in-place, em toda a árvore
find . -name '*.md' -print0 | xargs -0 sed -i -E 's/[[:space:]]+$//'
O ripgrep usa a crate regex do Rust (estilo RE2, tempo linear, sem lookbehind). grep -E e sed -E usam regex estendida do POSIX, que não tem \d; use [0-9] e [[:digit:]] no lugar. Quando os dados são JSON, troque regex por jq, e veja a cheat sheet de jq como ficha de referência paralela.
11. Armadilhas comuns
11.1 Esquecer de escapar .
Um bug real que já mandamos para produção: um redator de log devia mascarar endereços IP.
// Errado — também casa com '192a168b1c1'
/(\d+).(\d+).(\d+).(\d+)/.test('192a168b1c1'); // true
// Certo
/(\d+)\.(\d+)\.(\d+)\.(\d+)/.test('192a168b1c1'); // false
Dentro de uma classe de caracteres, . já é literal, então [.] e \. ambos funcionam. Em qualquer outro lugar, escape.
11.2 .* guloso devora demais
'<a href="x"><b>bold</b></a>'.match(/<(.*)>/)[1];
// 'a href="x"><b>bold</b></a' — a coisa inteira!
O .* guloso varre até o fim da string e depois volta até o > casar, ou seja, o último > da entrada. Ou vá preguiçoso (.*?) ou, mais rápido e claro, use uma classe negada ([^>]*).
11.3 Âncoras multiline
Confusão comum: ^ e $ não casam com caracteres de nova linha por padrão. Eles casam com posições no início e no fim da entrada inteira. Adicionar a flag m é o que os transforma em âncoras por linha. Adicionar a flag s é o que permite que . cruze novas linhas. São ortogonais e, para parsing de log, você normalmente quer as duas.
11.4 ReDoS e como desarmá-lo
ReDoS (negação de serviço por regex) é a versão grau-de-produção do backtracking catastrófico. As correções:
- Análise estática: ferramentas como
safe-regex,rechecke a regrano-misleading-character-classdo ESLint pegam os padrões perigosos antes do deploy. - Grupos atômicos (Python
regex, PCRE, Ruby, Java):(?>...)impede o engine de reentrar no grupo durante o backtrack. - Quantificadores possessivos (
*+,++,?+em PCRE/Java): mesma ideia, sintaxe mais curta. - Mude para um engine sem backtracking: o
regexpdo Go, RE2, a crateregexdo Rust e o bindingre2para Python rodam em tempo linear. ripgrep é o deploy mais popular de RE2 no mundo real. - Valide primeiro o tamanho da entrada. Uma bomba de regex de 10 KB é um bug; um teto de 10 bytes na entrada é uma linha de código.
Para um inventário mais amplo das ferramentas do dia a dia que combinam com regex (formatadores, decodificadores, conversores), veja nosso guia de ferramentas para desenvolvedores.
Antes de mandar um padrão complexo para produção, teste-o de forma interativa. O regex101.com alterna entre os flavors PCRE, JavaScript, Python e Go, explica cada token e mostra o backtracking para você identificar padrões catastróficos.
12. FAQ
Qual a diferença entre * e + em regex?
* casa com zero ou mais ocorrências (pode casar com uma string vazia); + casa com uma ou mais (precisa de pelo menos uma). a* casa com '', 'a', 'aaaa'. a+ casa com 'a' e 'aaaa', mas não com ''.
Como casar várias linhas com regex?
Ligue a flag multiline (/.../m em JavaScript, re.MULTILINE em Python) para que ^ e $ ancorem em cada linha. Para deixar . também cruzar novas linhas, acrescente a flag dotall (s em JavaScript, re.DOTALL em Python).
Regex é a mesma coisa em JavaScript e Python?
A sintaxe central (quantificadores, âncoras, classes de caracteres, grupos básicos) é 90% igual. As duas diferenças reais: JavaScript (ES2018+) suporta lookbehind de tamanho variável e escreve grupos nomeados como (?<name>...); o re da stdlib do Python exige lookbehind de largura fixa e usa (?P<name>...). Para lookbehind de tamanho variável em Python, instale o pacote regex do PyPI.
Por que minha regex tem backtracking catastrófico?
Você tem quantificadores aninhados com matches sobrepostos, como (a+)+ ou (a|a)*. Em uma entrada que quase casa mas falha perto do fim, o engine tenta cada divisão do quantificador interno, ou seja, um número exponencial de caminhos. Conserte com um grupo atômico (?>a+)+, um quantificador possessivo a++ ou mudando para um engine sem backtracking como RE2 ou o regexp do Go.
Posso usar lookbehind em JavaScript?
Sim. Lookbehind positivo (?<=...) e negativo (?<!...) estão no V8 (Chrome, Node.js), no SpiderMonkey (Firefox) e no JavaScriptCore (Safari 16.4+) desde ES2018. Lookbehind de tamanho variável é suportado. Para Safaris mais antigos, transpile com Babel ou faça feature-detect com um try/catch ao redor de new RegExp.
Como casar um ponto . literal em regex?
Escape com uma contrabarra: \. casa com um ponto literal. Dentro de uma classe de caracteres, o ponto já é literal: tanto [.] quanto [\.] funcionam. Fora de uma classe, um . sem escape é um metacaractere que significa “qualquer caractere exceto nova linha” (ou qualquer caractere mesmo com a flag dotall).
O que significa \s em regex?
\s casa com qualquer caractere de espaço em branco — espaço, tab, nova linha, retorno de carro. Em modo Unicode também casa com NBSP. \S é o inverso.
Expressões regulares fazem distinção entre maiúsculas e minúsculas?
Por padrão, sim. Use a flag i em JavaScript (/cat/i) ou re.IGNORECASE / (?i) em Python.