Introducción a las expresiones regulares en Rust
Las expresiones regulares (regex) son una herramienta poderosa para buscar, extraer y reemplazar texto según un patrón determinado. En Rust, para trabajar con expresiones regulares se utiliza el crate regex, una de las bibliotecas más populares y eficientes del ecosistema. En este artículo, exploraremos los fundamentos del uso de regex en Rust, desde la instalación hasta ejemplos prácticos.
¿Por qué vale la pena aprender expresiones regulares en Rust? El lenguaje ofrece un manejo de texto seguro y rápido, y el crate regex garantiza la ausencia de fugas de memoria y una alta velocidad de ejecución. Esto convierte a Rust en una excelente opción para analizar registros, validar formularios, procesar archivos de configuración y otras tareas.
Instalación y configuración del crate regex
Para comenzar, agrega la dependencia regex a tu archivo Cargo.toml:
[dependencies]regex = "1.10"Luego, importa el módulo en tu código:
use regex::Regex;La estructura principal con la que trabajarás es Regex. Puedes crear una instancia usando el método Regex::new(), que devuelve un Result, ya que el patrón podría ser inválido.
fn main() { let re = Regex::new(r"^\\d{3}-\\d{2}-\\d{4}$").unwrap(); println!("Regex creado: {}", re.as_str());}Nota: el patrón se escribe en cadenas crudas (r"...") para evitar escapar las barras invertidas.
Operaciones básicas con expresiones regulares
1. Verificar coincidencia: is_match
El método is_match devuelve true si el patrón se encuentra en la cadena:
use regex::Regex;
fn main() { let re = Regex::new(r"hello").unwrap(); let text = "hello world"; if re.is_match(text) { println!("¡Coincidencia encontrada!"); } else { println!("No hay coincidencias"); }}Salida: ¡Coincidencia encontrada!
2. Buscar la primera coincidencia: find
El método find devuelve Option<Match> — la primera coincidencia con información de posición:
use regex::Regex;
fn main() { let re = Regex::new(r"\\d+").unwrap(); let text = "Código: 12345, precio: 678"; if let Some(m) = re.find(text) { println!("Encontrado: '{}' (posición {}..{})", m.as_str(), m.start(), m.end()); }}Salida: Encontrado: '12345' (posición 8..13)
3. Buscar todas las coincidencias: find_iter
Para obtener todas las coincidencias, usa el 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()); }}Salida:
Número: 42Número: 100Número: 74. Extraer grupos: captures
Los grupos en el patrón (indicados con paréntesis) permiten extraer partes de la coincidencia:
use regex::Regex;
fn main() { let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap(); let email = "user@example.com"; if let Some(caps) = re.captures(email) { println!("Email completo: {}", &caps[0]); println!("Nombre: {}", &caps[1]); println!("Dominio: {}", &caps[2]); println!("Zona: {}", &caps[3]); }}Salida:
Email completo: user@example.comNombre: userDominio: exampleZona: comEjemplos prácticos de uso
Ejemplo 1: Validación de número de teléfono
Verifiquemos si una cadena coincide con el formato de un número ruso (por ejemplo, +7-XXX-XXX-XX-XX):
use regex::Regex;
fn v