5. Expressions régulières avec la crate regex

Les expressions régulières sont l’outil indispensable pour détecter, extraire et transformer des patterns dans du texte. En Rust, la crate regex fournit un moteur de regex performant et sûr. Dans cette unité, vous apprendrez à intégrer une dépendance externe, à construire des expressions régulières pour capturer des structures comme des numéros de référence documentaire, et à extraire les groupes capturés.

 

Ajouter la crate regex au projet

En Rust, les bibliothèques externes s’appellent des crates. On les ajoute dans Cargo.toml ou avec la commande cargo add :

cargo add regex
cargo add once_cell

Cargo modifie automatiquement Cargo.toml :

[dependencies]
regex    = "1"
once_cell = "1"

 

Construire et utiliser un Regex

La construction d’un objet Regex peut échouer si le pattern est invalide, donc elle retourne un Result. Une fois compilé, l’objet peut être réutilisé efficacement :

use regex::Regex;

fn main() {
    let re = Regex::new(r"DOC-d{4}-d{3}").unwrap();
    let texte = "Voir le document DOC-2024-042 pour les détails.";

    println!("Contient une ref : {}", re.is_match(texte));

    if let Some(m) = re.find(texte) {
        println!("Trouvé : {} (pos {}-{})", m.as_str(), m.start(), m.end());
    }

    for m in re.find_iter(texte) {
        println!("Occurrence : {}", m.as_str());
    }
}

 

Groupes de capture nommés

Les groupes de capture entre parenthèses permettent d’extraire des parties spécifiques. Les groupes nommés ((?P<nom>...)) rendent le code encore plus lisible :

use regex::Regex;

fn main() {
    let re = Regex::new(
        r"(?P<prefixe>[A-Z]{2,6})-(?P<annee>d{4})-(?P<numero>d{3})"
    ).unwrap();

    let texte = "Références : DOC-2024-042 et FACT-2023-007";

    for caps in re.captures_iter(texte) {
        println!(
            "Préfixe={}, Année={}, N°={}",
            &caps["prefixe"], &caps["annee"], &caps["numero"]
        );
    }
}

 

Remplacer des patterns

La méthode replace_all permet de substituer toutes les occurrences. Les références aux groupes capturés s’utilisent avec $nom :

use regex::Regex;

fn reformater(texte: &str) -> String {
    let re = Regex::new(
        r"(?P<prefixe>[A-Z]{2,6})-(?P<annee>d{4})-(?P<numero>d{3})"
    ).unwrap();
    re.replace_all(texte, "[$prefixe] N°$numero/$annee").to_string()
}

fn main() {
    let texte = "Voir DOC-2024-042 et FACT-2023-007";
    println!("{}", reformater(texte));
    // "Voir [DOC] N°042/2024 et [FACT] N°007/2023"
}

 

Optimiser avec LazyLock

Compiler un Regex à chaque appel de fonction est coûteux. On utilise LazyLock (Rust 1.80+) ou once_cell::sync::Lazy pour ne le compiler qu’une fois :

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

static RE_REF: Lazy<Regex> = Lazy::new(|| {
    Regex::new(r"(?P<prefixe>[A-Z]{2,6})-(?P<annee>d{4})-(?P<numero>d{3})").unwrap()
});

fn detecter(texte: &str) -> bool {
    RE_REF.is_match(texte)  // RE_REF compilé une seule fois au premier appel
}
Points clés :

  • Ajouter une dépendance avec cargo add nom-crate
  • Regex::new(r"...") — utilisez les raw strings (r"...") pour éviter les doubles backslashes
  • Les groupes nommés (?P<nom>...) rendent les captures lisibles
  • Utilisez Lazy pour compiler le Regex une seule fois au démarrage du programme
SEE ALL Add a note
YOU
Add your Comment