Expresiones regulares en Rust con ejemplos: en la práctica
\n\nLas expresiones regulares (regex) son una herramienta poderosa para trabajar con texto. En Rust, a pesar de su tipado estricto y su enfoque en la seguridad, el trabajo con expresiones regulares se implementa de manera eficiente y conveniente gracias a la crate regex. En este artículo, analizaremos cómo usar expresiones regulares en Rust en la práctica: desde la instalación hasta escenarios complejos de procesamiento de cadenas.
Veremos las operaciones principales: búsqueda, extracción, reemplazo y validación. Todos los ejemplos de código están escritos en Rust y listos para usar.
\n\nInstalación y configuración de la crate regex
\n\nPara trabajar con expresiones regulares en Rust se utiliza una crate externa, pero muy popular, llamada regex. No está incluida en la biblioteca estándar, por lo que debe agregarse al proyecto.
Agregue la dependencia al archivo Cargo.toml:
[dependencies]\nregex = "1"\n\nDespués de esto, en el código puede importar los tipos principales:
\n\nuse regex::Regex;\n\nLa crate regex compila la expresión regular en un autómata finito, lo que garantiza un alto rendimiento. Los errores de compilación del patrón se detectan en tiempo de ejecución (a través de Result), lo que hace que el código sea confiable.
Conceptos básicos: búsqueda de coincidencias en una cadena
\n\nLa forma más sencilla de verificar si una cadena coincide con un patrón es usar el método is_match. Veamos un ejemplo de verificación de la presencia de una dirección de correo electrónico en un texto.
use regex::Regex;\n\nfn main() {\n let re = Regex::new(r"\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b").unwrap();\n let text = "Contáctenos en support@example.com.";\n\n if re.is_match(text) {\n println!("¡Correo electrónico encontrado!");\n } else {\n println!("Correo electrónico no encontrado.");\n }\n}\n\nEl método Regex::new toma una cadena con el patrón y devuelve un Result. unwrap() se usa aquí por simplicidad, pero en código de producción se deben manejar los errores correctamente.
Para buscar todas las coincidencias se usa el método find_iter, que devuelve un iterador sobre objetos Match:
use regex::Regex;\n\nfn main() {\n let re = Regex::new(r"\\d+").unwrap();\n let text = "Precios: 100, 250 y 500 rublos.";\n\n for mat in re.find_iter(text) {\n println!("Número encontrado: {}", mat.as_str());\n }\n}\n\nEste código mostrará:
\n\nNúmero encontrado: 100\nNúmero encontrado: 250\nNúmero encontrado: 500\n\nExtracción de datos usando grupos de captura
\n\nLos grupos de captura permiten extraer no solo toda la coincidencia, sino sus partes individuales. Por ejemplo, analizar una fecha en el formato "dd-mm-aaaa".
\n\nuse regex::Regex;\n\nfn main() {\n let re = Regex::new(r"(\\d{2})-(\\d{2})-(\\d{4})").unwrap();\n let text = "Hoy es 15-03-2024.";\n\n if let Some(caps) = re.captures(text) {\n println!("Día: {}", &caps[1]);\n println!("Mes: {}", &caps[2]);\n println!("Año: {}", &caps[3]);\n }\n}\n\nLa indexación de grupos comienza en 1 (el grupo 0 es toda la coincidencia). El método captures devuelve Option<Captures>. Si se encuentra una coincidencia, podemos acceder a los grupos mediante el índice.
Para extraer todas las apariciones con grupos se usa captures_iter:
use regex::Regex;\n\nfn main() {\n let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap();\n let text = "correos: user@host.com, admin@site.org";\n\n for caps in re.captures_iter(text) {\n println!("Usuario: {}, dominio: {}, zona: {}", &caps[1], &caps[2], &caps[3]);\n }\n}\n\nEste enfoque es indispensable al analizar registros, archivos de configuración o extraer datos estructurados de texto no estructurado.
\n\nReemplazo de texto según un patrón
\n\nLa crate regex