Introdução às expressões regulares em Rust
Expressões regulares (regex) são uma ferramenta poderosa para buscar, extrair e substituir texto de acordo com um padrão definido. Em Rust, para trabalhar com expressões regulares, utiliza-se o crate regex — uma das bibliotecas mais populares e performáticas do ecossistema. Neste artigo, abordaremos os fundamentos do trabalho com regex em Rust, desde a instalação até exemplos práticos.
Por que vale a pena aprender expressões regulares em Rust? A linguagem oferece manipulação de texto segura e rápida, e o crate regex garante ausência de vazamentos de memória e alta velocidade de execução. Isso torna Rust uma excelente escolha para análise de logs, validação de formulários, processamento de arquivos de configuração e outras tarefas.
Instalação e inclusão do crate regex
Para começar, adicione a dependência regex ao seu arquivo Cargo.toml:
[dependencies]regex = "1.10"Em seguida, importe o módulo no código:
use regex::Regex;A estrutura principal com a qual você trabalhará é Regex. Você pode criar uma instância usando o método Regex::new(), que retorna um Result, pois o padrão pode ser inválido.
fn main() { let re = Regex::new(r"^\\d{3}-\\d{2}-\\d{4}$").unwrap(); println!("Regex criado: {}", re.as_str());}Observe: o padrão é escrito em strings brutas (r"...") para evitar a necessidade de escapar barras invertidas.
Operações básicas com expressões regulares
1. Verificação de correspondência: is_match
O método is_match retorna true se o padrão for encontrado na string:
use regex::Regex;
fn main() { let re = Regex::new(r"hello").unwrap(); let text = "hello world"; if re.is_match(text) { println!("Correspondência encontrada!"); } else { println!("Nenhuma correspondência"); }}Saída: Correspondência encontrada!
2. Busca da primeira correspondência: find
O método find retorna Option<Match> — a primeira correspondência com informações de posição:
use regex::Regex;
fn main() { let re = Regex::new(r"\\d+").unwrap(); let text = "Código: 12345, preço: 678"; if let Some(m) = re.find(text) { println!("Encontrado: '{}' (posição {}..{})", m.as_str(), m.start(), m.end()); }}Saída: Encontrado: '12345' (posição 8..13)
3. Busca de todas as correspondências: find_iter
Para obter todas as correspondências, use o iterador find_iter:
use regex::Regex;
fn main() { let re = Regex::new(r"\\d+").unwrap(); let text = "Números: 42, 100, 7"; for m in re.find_iter(text) { println!("Número: {}", m.as_str()); }}Saída:
Número: 42Número: 100Número: 74. Extração de grupos: captures
Grupos no padrão (indicados por parênteses) permitem extrair partes da correspondência:
use regex::Regex;
fn main() { let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap(); let email = "usuario@exemplo.com"; if let Some(caps) = re.captures(email) { println!("Email completo: {}", &caps[0]); println!("Nome: {}", &caps[1]); println!("Domínio: {}", &caps[2]); println!("Zona: {}", &caps[3]); }}Saída:
Email completo: usuario@exemplo.comNome: usuarioDomínio: exemploZona: comExemplos práticos de uso
Exemplo 1: Validação de número de telefone
Vamos verificar se a string corresponde ao formato de número russo (por exemplo, +7-XXX-XXX-XX-XX):
use regex::Regex;
fn v