Aller au contenu

Expressions Régulières en Java

Introduction

Les expressions régulières (ou regex) sont un outil puissant pour :

En Java, elles sont gérées par le package java.util.regex, avec deux classes principales :


Classes et méthodes

Classe/Interface Rôle Méthodes/Utilisation Typique
java.util.regex.Pattern Compile une expression régulière en un objet réutilisable. compile(), matcher(), split()
java.util.regex.Matcher Applique un Pattern à une chaîne et permet de parcourir les correspondances. find(), group(), replaceAll(), matches()
PatternSyntaxException Exception levée en cas d’erreur de syntaxe dans une regex. Géré via un try-catch.
CharSequence Interface implémentée par String, StringBuilder, etc. pour les opérations de pattern. Utilisée par Pattern et Matcher.
String Implémente CharSequence et offre des méthodes basiques pour les regex. matches(), replaceAll(), split().

2. Classes de caractères

Les classes de caractères permettent de définir des ensembles de caractères pour construire notre modèle (pattern).

Syntaxe Description Exemple Correspond à
\d Chiffre (0-9) \d\d “42”, “99”
\w Caractère alphanumérique (a-z, A-Z, 0-9, _) \w+ “Java_123”
\s Espace (espace, tabulation, nouvelle ligne) \s+ ” “, “\t”, “\n”
\D Tout sauf un chiffre \D+ “abc”, “@#”
\W Tout sauf un caractère alphanumérique \W+ ”!@#”, “ “
\S Tout sauf un espace \S+ “abc”, “123”
. N’importe quel caractère (sauf nouvelle ligne) a.c “abc”, “a1c”, “a-c”
[abc] Un des caractères entre crochets [aeiou] “a”, “e”, “i”
[^abc] Tout sauf les caractères entre crochets [^0-9] “a”, “@”, “ “

Quantificateurs

Les quantificateurs spécifient combien de fois un élément doit apparaître dans notre modèle.

Syntaxe Description Exemple Correspond à
* 0 ou plusieurs occurrences a* ””, “a”, “aaaa”
+ 1 ou plusieurs occurrences a+ “a”, “aaaa” (pas “”)
? 0 ou 1 occurrence colou?r “color”, “colour”
{n} respecter n occurrences \d{3} “123”, “987”
{n,} au moins n occurrences \d{2,} “12”, “12345”
{n,m} entre n et m occurrences (inclus) v \d{2,4} “12”, “123”, “1234”

Méthodes Utiles dans String

La classe String offre des méthodes pratiques pour utiliser les regex sans créer explicitement de Pattern ou Matcher.

Méthode Description Exemple
matches(regex) vérifie si toute la chaîne correspond à la regex. "12/31/2023".matches("\\d{2}/\\d{2}/\\d{4}")true
split(regex) divise la chaîne en un tableau selon la regex. "1,2,3".split(",")["1", "2", "3"]
replaceAll(regex, replacement) remplace toutes les occurrences de la regex par replacement. "coucou".replaceAll("u", "in")"coincoin"
replaceFirst(regex, replacement) remplace la première occurrence de la regex. "coucou".replaceFirst("c", "t")"toutou"

Exemples de codes pratiques

Valider des dates

la notion degroup est expliquée plus loin.

import java.util.regex.*;

public class DateValidateur {
    public static void main(String[] args) {
        String date = "12/30/1969";
        // Regex pour MM/DD/YYYY ou MM-DD-YYYY
        Pattern p = Pattern.compile("^(\\d{2})[-/](\\d{2})[-/](\\d{2}(?:\\d{2})?)$");
        Matcher m = p.matcher(date);
        // la syntaxe est monPattern.matcher(maDate)

        if (m.find()) {
            String mois = m.group(1);
            String jour = m.group(2);
            String annee = m.group(3);
            System.out.printf("Date valide : %s-%s-%s\n", annee, mois, jour); // version anglaise
        } else {
            System.out.println("Format de date invalide.");
        }
    }
}

Explications :

Substitution simple

import java.util.regex.*;

public class SubstitutionSimple {
    public static void main(String[] args) {
        String text = "Hello world. <br>";
        // Remplacer <br> par <br /> pour la conformité XHTML (web)
        String resultat = text.replaceAll("<br>", "<br />");
        System.out.println(resultat);  // affiche "Hello world. <br />"
    }
}

Transformation des URLs en liens HTML

import java.util.regex.*;

public class UrlToLink {
    public static void main(String[] args) {
        String text = "Visitez https://formation-java-mer.numerosoft.fr/semaine/tp/ pour plus d'infos.";
        String regex = "\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);
        String resultat = m.replaceAll("<a href=\"$0\">$0</a>");
        System.out.println(resultat);
        // Affiche: Visitez <a href="https://formation-java-mer.numerosoft.fr/semaine/tp/">https://formation-java-mer.numerosoft.fr/semaine/tp/</a> pour plus d'infos.
    }
}

Explications :

Extraction des groupes d’un courriel

import java.util.regex.*;

public class ExtracteurCourriel {
    public static void main(String[] args) {
        String text = "Contactez-nous à support@ca.com ou ventes@ca.org.";
        String regex = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}\\b";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);

        while (m.find()) {
            System.out.println("Courriel trouvé : " + m.group());
        }
    }
}

Résultat :

Email trouvé : support@ca.com
Email trouvé : ventes@ca.org

On pourrait aller plus loin avec les groups capturants : ( … )

Un group devient intéressant quand on ajoute des parenthèses dans le regex.

Exemple modifié, on découpe l’email avec les parenthèse pour créer des group à l’intérieur du regex :

String regex = "([A-Za-z0-9._%+-]+)@([A-Za-z0-9.-]+)\\.([A-Za-z]{2,6})";

On a 3 groups :

Code complet :

Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(text);

while (m.find()) {
    System.out.println("Courriel complet : " + m.group(0)); // on met l'indice 0 pour avoir toute la chaine
    System.out.println("Utilisateur      : " + m.group(1));
    System.out.println("Domaine      : " + m.group(2));
    System.out.println("Extension    : " + m.group(3));
    System.out.println("----");
}

Résultats :

Email complet : support@ca.com
User         : support
Domaine      : ca
Extension    : com
----
Email complet : ventes@ca.org
User         : sales
Domaine      : ca
Extension    : org
----

Pour infos, on peut simplifier l’indentification des groupes depuis java 7+.

String regex = "(?<user>[A-Za-z0-9._%+-]+)@(?<domain>[A-Za-z0-9.-]+)\\.(?<ext>[A-Za-z]{2,6})";

Puis :

System.out.println(m.group("user"));
System.out.println(m.group("domain"));
System.out.println(m.group("ext"));

Échappement des caractères

En Java, les backslashes () dans les expressions régulières doivent être doublés car ils sont aussi des caractères d’échappement dans les chaînes de caractères en Java.

Caractère Regex Dans une chaîne Java Exemple
\d \\d "\\d" : correspond à un chiffre
\. \\. "\\." : correspond à un point
\n \\n "\\n" : correspond à un saut de ligne

Exemple :

String regex = "\\d{3}-\\d{2}-\\d{4}";  // Correspond à "123-45-6789"

Bonnes pratiques

Précompiler les Pattern

Si une regex est utilisée plusieurs fois, compilez-la une seule fois avec Pattern.compile() pour des performances optimales.

private static final Pattern DATE_PATTERN = Pattern.compile("\\d{2}/\\d{2}/\\d{4}");

Utiliser des commentaires

Pour les regex complexes, utilisez le flag Pattern.COMMENTS pour ajouter des commentaires. Ci-dessous, les commentaires sont les dièzes Jour, Mois et Année.

String regex = """
    \\d{2}   # Jour
    /
    \\d{2}   # Mois
    /
    \\d{4}   # Année
""";
Pattern p = Pattern.compile(regex, Pattern.COMMENTS);

Gérer les exceptions

Toujours attraper PatternSyntaxException pour les regex invalides.

try {
    Pattern p = Pattern.compile("[a-z");
} catch (PatternSyntaxException e) {
    System.err.println("Erreur dans la regex: " + e.getMessage());
}

Éviter la sur-utilisation

Les regex peuvent devenir illisibles. Pour des parsings complexes, envisagez un parseur dédié (JSON avec Jackson).

Exercice Pratique

Énoncé : Écrivez une regex pour valider un numéro de téléphone français (format : +33 1 23 45 67 89 ou 01 23 45 67 89).

Solution possible :

import java.util.regex.*;

public class ValiderNumeroTelephone {
    public static void main(String[] args) {
        String tel = "+33 7 23 45 67 89";
       String regex = "^(\\+33[ \\-]?|0)[67]([ \\-]?\\d{2}){4}$";
        System.out.println(tel.matches(regex));  // true
    }
}

Explications :

Ressources