1001Ferramentas
🦀Validadores

Validador de Regex Rust

Compila uma regex usando o subset de sintaxe da crate regex (Rust). Indica recursos não suportados (lookarounds, backrefs).

A crate regex do Rust prioriza performance linear e não suporta lookarounds nem backreferences.

A crate regex do Rust: tempo linear por design

A crate regex, escrita por Andrew Gallant (burntsushi), e a biblioteca padrao de fato para expressoes regulares em Rust. Diferente da PCRE, PCRE2, do re do Python ou do java.util.regex, a crate Rust garante casamento em tempo linear no tamanho da entrada. Nao ha recursao, nao ha backtracking e, portanto, nao ha superficie de ataque ReDoS — a mesma propriedade que permite ao ripgrep (tambem do burntsushi) varrer gigabytes de codigo em segundos.

O trade-off e paridade de features. Para manter linearidade, a crate omite deliberadamente os dois recursos mais associados a backtracking catastrofico: backreferences (\1, \2) e lookarounds ((?=...), (?!...), (?<=...), (?<!...)). Se voce precisa, a crate irma fancy-regex envelopa a regex e cai num motor com backtracking — ao custo da garantia linear.

Interna do motor: DFA preguicoso sobre NFA Pike VM

A crate compila o padrao em uma NFA (Pike VM) e, durante o casamento, constroi sob demanda um DFA preguicoso — so os estados realmente visitados sao materializados, mantendo a memoria limitada. Em cargas predominantemente ASCII o runtime ainda despacha para memchr, aho-corasick (multipadrao), boyer-moore e scanners literais acelerados por SIMD. Esta abordagem hibrida e por que o ripgrep bate o GNU grep e o silver searcher em arvores grandes de codigo.

Na pratica, Regex::new("foo") pode levar dezenas de microssegundos porque constroi o automato. Para uso repetido, cacheie regex compilados com once_cell::sync::Lazy ou com o macro mais antigo lazy_static! — nunca compile dentro de um loop quente.

Sintaxe suportada: Unicode-first, compativel com RE2

A gramatica e intencionalmente proxima a do regexp do Go e do RE2 do Google, com extensoes:

  • Classes de caracteres: [a-z], negacao [^0-9], intersecao e subtracao dentro de [...].
  • Categorias Unicode: \p{Greek}, \p{Letter}, \p{Decimal_Number} — Unicode 15 por padrao.
  • Grupos nomeados: (?P<year>\d{4}), recuperado via .name("year").
  • Flags: (?i) case-insensitive, (?m) multiline, (?s) ponto casa newline, (?x) extended (ignora whitespace).
  • Quantificadores: gulosos */+/?, lazy *?/+?/??, limitados {n,m}.
  • Ancoras: ^, $, \b fronteira de palavra, \A / \z inicio/fim absolutos.

Performance vs PCRE2, Python e Hyperscan

Benchmarks independentes (rebar, tambem do burntsushi) classificam os motores aproximadamente assim em cargas gerais: Hyperscan (Intel) ≈ Rust regex > Go regexp > PCRE2-JIT > PCRE2 > Python re > Ruby Onigmo. O Hyperscan e mais rapido em cenarios multi-padrao especificos (IDS de rede); o Rust ganha em busca de codigo generica. O PCRE2 ganha em quantidade de features.

Um anti-padrao classico que destroi motores com backtracking e a quantificacao aninhada como (a+)+$ ou (.*)*. Sobre 30 caracteres de "aaaaaa..." seguidos de "b", a PCRE explode em milhoes de passos; a crate Rust termina em microssegundos porque o DFA visita cada caractere no maximo uma vez.

Uso idiomatico e ecossistema

use once_cell::sync::Lazy;
use regex::Regex;

static RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap()
});

fn parse(s: &str) -> Option<(&str, &str, &str)> {
    let c = RE.captures(s)?;
    Some((c.name("y")?.as_str(),
          c.name("m")?.as_str(),
          c.name("d")?.as_str()))
}

Casos onde a garantia linear brilha: parsing de logs a milhoes de linhas/seg, syntax highlighting em editores (Helix, Zed), busca de codigo (ripgrep, fd), roteadores HTTP (o actix-web usa regex para parametros de path) e qualquer servico que aceite padroes do usuario — expor PCRE2 a entrada nao confiavel e um vetor conhecido de DoS.

Testes e ferramentas

  • rustexp (rustexp.lpil.uk) — playground com pegada oficial para a crate Rust.
  • regex101 com sabor Rust — explicacao interativa, mas atencao: a sintaxe de lookaround aparece como suportada porque o site cai na PCRE.
  • cargo test — escreva testes unitarios afirmando casamentos positivos e negativos; a crate e deterministica e reproduzivel entre plataformas.
  • crate regex-syntax — API somente de parsing para validar um padrao em tempo de compilacao ou em build scripts.

FAQ

A regex do Rust suporta backreferences?

Nao. A crate principal recusa padroes com \1, \2 etc. porque exigem backtracking. Se precisar, use a crate fancy-regex, que envelopa a regex e cai num motor com backtracking quando o padrao demanda.

A crate e imune a ReDoS?

Sim. O casamento e linear no tamanho da entrada e a memoria do DFA preguicoso e limitada (e configuravel). Padroes que paralisam a PCRE — como (a+)+$ — terminam em microssegundos.

Como se compara com a PCRE2?

A PCRE2 tem toda feature ja inventada (lookarounds, backreferences, subrotinas, recursao) e o PCRE2-JIT e rapido. A crate Rust abre mao dessas features em troca de seguranca em tempo linear e scan literal por SIMD. Escolha PCRE2 por expressividade, Rust por seguranca e busca de codigo.

Da para usar o mesmo padrao em Go e Rust?

Em geral sim — ambos implementam sintaxe RE2. O Rust adiciona classes de propriedade Unicode e algumas flags extras que faltam no Go, mas o subconjunto comum transfere limpo.

Por que meu regex Rust e lento na primeira chamada?

Regex::new() constroi o automato. Tire a compilacao de loops quentes usando once_cell::sync::Lazy. Em regime, o DFA preguicoso esta entre os motores mais rapidos disponiveis.

Ferramentas Relacionadas