Pular para o conteúdo

Expressões regulares

fundamentos
Padrão Casa com
. Qualquer caractere (menos nova linha, por padrão)
\d / \D Dígito / não dígito
\w / \W Letra, dígito ou _ / o contrário
\s / \S Espaço em branco / o contrário
[abc] a, b ou c
[^abc] Qualquer um exceto a, b, c
[a-z0-9] Faixa
[[:digit:]] Classe POSIX (grep, sed)
Padrão Significa
* Zero ou mais
+ Um ou mais
? Zero ou um (opcional)
{3} Exatamente 3
{2,5} De 2 a 5
{2,} 2 ou mais
*?, +?, ?? Versão preguiçosa (mínimo possível)
Padrão Significa
^ / $ Início / fim da linha
\b Fronteira de palavra
(abc) Grupo de captura (\1, $1 na substituição)
(?:abc) Grupo sem captura
(?<nome>abc) Grupo nomeado (PCRE, Go, Python)
a|b Alternativa
(?=abc) / (?!abc) Lookahead positivo / negativo (não em RE2)

A confusão mais frequente:

texto: <a href="x">link</a>
<.+> → casa a linha inteira (ganancioso)
<.+?> → casa apenas <a href="x"> (preguiçoso)
<[^>]+> → casa apenas <a href="x"> (melhor: mais rápido e sem backtracking)

Prefira a terceira forma sempre que possível: negar a classe é mais eficiente que quantificador preguiçoso.

Ferramenta Dialeto Observação
grep BRE +, ?, |, () precisam de \
grep -E / egrep ERE Sintaxe moderna, sem escapes
grep -P PCRE \d, lookahead (nem toda build tem)
sed BRE Use sed -E para ERE
awk ERE —
ripgrep / Go / Rust RE2 Sem lookahead nem backreference; tempo linear
Python re PCRE-like \d funciona
PromQL RE2, ancorado status=~"5.." equivale a ^5..$
Prometheus relabel RE2, ancorado Idem
JavaScript Própria, próxima de PCRE —

Na dúvida em shell, use grep -E. \d não funciona em grep sem -P.

Janela do terminal
# IPv4 (aproximado, suficiente para log)
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
# timestamp ISO
grep -Eo '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}' app.log
# status HTTP 5xx em log de acesso comum
grep -E '" 5[0-9]{2} ' access.log
# extrair valor de campo JSON simples
grep -oP '"trace_id"\s*:\s*"\K[^"]+' app.log
# e-mail (aproximação prática — validação real não se faz por regex)
grep -Eo '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' arquivo
# possíveis segredos
grep -nE '(AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|-----BEGIN [A-Z ]*PRIVATE KEY-----)' -r .
# top de IPs no log
grep -Eo '^([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort | uniq -c | sort -rn | head
# substituição com grupo
sed -E 's/^([0-9-]+)T([0-9:]+).*/\1 \2/' app.log
# Prometheus relabel: mantém apenas alvos anotados
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
# extrai parte do label
- source_labels: [__meta_kubernetes_pod_name]
regex: "(.*)-[a-z0-9]+-[a-z0-9]+" # tira o sufixo do ReplicaSet
target_label: workload
replacement: "$1"
# Kubernetes: validação em CRD
pattern: "^[a-z][a-z0-9-]{2,29}$"
# Terraform
condition = can(regex("^[a-z][a-z0-9-]{2,29}$", var.nome))
  • Regex em PromQL e no relabel é ancorada: route=~"api" só casa a rota exatamente api; use route=~".*api.*".
  • . sem escape casa qualquer caractere: 10.0.0.1 casa com 10x0y0z1.
  • Backtracking catastrófico ((a+)+b) trava o processo — RE2 (Go, ripgrep) não sofre disso, PCRE sofre.
  • Escape de / em sed: use outro delimitador, sed 's|a|b|'.
  • Em YAML, coloque a regex entre aspas simples para evitar interpretação de \.
  • Validar e-mail, URL ou CPF “corretamente” por regex é ilusão; valide o formato mínimo e confirme por outro meio.