El crate regex de Rust tiene una particularidad que lo distingue del de otros lenguajes: garantiza un tiempo de ejecución lineal con la longitud del texto. A cambio no admite retrovisores ni referencias hacia atrás, y gracias a eso es inmune a los bloqueos por retroceso catastrófico que afectan a otros motores.
También te puede interesar
La dependencia
cargo add regex
[dependencies] regex = "1.13.1"
Buscar, capturar y sustituir
use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let texto = "Pedido 2026-10-02 de ada@ejemplo.com por 149,90 €; soporte en hola@decodigo.com";
let correo = Regex::new(r"[\w.+-]+@[\w-]+\.[\w.]+")?;
println!("¿hay correo? {}", correo.is_match(texto));
for c in correo.find_iter(texto) {
println!(" encontrado: {}", c.as_str());
}
let fecha = Regex::new(r"(?<anio>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})")?;
if let Some(c) = fecha.captures(texto) {
println!("fecha: día {} mes {} año {}", &c["dia"], &c["mes"], &c["anio"]);
}
let oculto = correo.replace_all(texto, "[correo oculto]");
println!("anonimizado: {oculto}");
Ok(())
}
salida¿hay correo? true encontrado: ada@ejemplo.com encontrado: hola@decodigo.com fecha: día 02 mes 10 año 2026 anonimizado: Pedido 2026-10-02 de [correo oculto] por 149,90 €; soporte en [correo oculto]
Los patrones van entre r"...", que es una cadena cruda: dentro de ella la barra invertida no se interpreta, así que se escribe \d y no \\d. Sin eso, cualquier expresión regular en Rust se vuelve ilegible.
Los grupos con nombre, (?<anio>...), permiten leer las capturas por su nombre en lugar de por su número, con &c["anio"]. Es bastante más robusto: si añades un grupo al principio, los números cambian y los nombres no.
Regex::new analiza y compila el patrón, que no es gratis. Dentro de un bucle es un error clásico: se recompila en cada vuelta. Lo correcto es construirla fuera, o guardarla en un static con LazyLock si se usa desde varios sitios.Lo que se usa a diario
| Qué quieres | Cómo |
|---|---|
| ¿Aparece el patrón? | re.is_match(t) |
| La primera coincidencia | re.find(t), da Option |
| Todas las coincidencias | re.find_iter(t) |
| Los grupos capturados | re.captures(t) |
| Sustituir todas | re.replace_all(t, "x") |
| Usar un grupo en la sustitución | "$anio" en el reemplazo |
| Partir por un patrón | re.split(t) |
| Sin distinguir mayúsculas | (?i) al principio del patrón |
(?<=...) ni referencias hacia atrás como \1. No es una carencia por hacer: esas construcciones son justamente las que permiten que una expresión regular tarde un tiempo exponencial con ciertas entradas, el problema conocido como retroceso catastrófico, que en un servidor web es una vía de denegación de servicio. El motor de Rust renuncia a ellas para poder garantizar tiempo lineal siempre. Si de verdad necesitas un retrovisor, casi siempre se puede reescribir el patrón o resolverlo con dos pasadas.El código de esta página se compiló y ejecutó con rustc 1.96.1 y regex 1.13.1 antes de publicarla; las salidas están copiadas de la ejecución real. Documentación oficial: regex en docs.rs.