Expressions régulières en Java — java.util.regex

08 Sep 2019 08 Sep 2019 5406 vues ESSADDOUKI Mostafa 14 min de lecture
Introduction
1 Nouveautés de Java 11 2 Différences entre JDK, JRE et JVM 3 Structure d'un programme Java - Hello World 4 Mots clés et conventions de dénomination en Java 5 Types de données intégrés en Java 6 Les variables en Java 7 Classes enveloppe - Number, Integer, Double ... 8 Lire les entrées clavier en Java
Structures de contrôle
9 Les opérateurs en Java 10 Les structures conditionnelles en Java 11 Les boucles en Java 12 Instructions de contrôle de boucle - break, continue
Chaines de caractères
13 Les chaines en Java - API String 14 Les chaines en Java - StringBuffer et StringBuilder 15 Les expressions régulières en Java
Programmation OO
16 Objets et classes en Java 17 Modificateurs d'accès Java - public, private, protected et package 18 Méthodes et surcharge des méthodes en Java 19 les constructeurs en Java 20 L'héritage en Java 21 Classes abstraites en Java 22 Interfaces et héritage multiple en Java 23 Les classes imbriquées en Java 24 Les singletons en Java 25 Classes et méthodes génériques 26 Interface fonctionnelle et expressions Lambda en Java
Tableaux et collections
27 Les tableaux en Java 28 Classe Arrays - java.util.Arrays 29 Les listes dynamiques - java.util.ArrayList 30 Les listes chaînées en Java - java.util.LinkedList 31 HashSet en Java - java.util.HashSet 32 HashMap en Java - java.util.HashMap
Gestion des fichiers
33 Comprendre les fichiers informatiques 34 Utilisation des classes Path et Files en Java 35 Lecture et écriture dans un fichier en Java 36 Fichiers à accès aléatoire en Java
Gestion d'exceptions
37 Gestion d'exceptions en Java 38 Créez vos propres classes d'exception en Java
Programmation concurrente
39 Introduction à la programmation concurrente en Java - Multi-threads 40 classe java.lang.Thread 41 Synchronisation des threads en Java
Cours Java pour les débutants — Étape 15 sur 41

Expressions régulières en Java — java.util.regex

  Prérequis

Maîtriser la classe String et ses méthodes de recherche. Comprendre les notions de pattern, de compilation et de correspondance. Avoir des bases sur la gestion des exceptions.

  Objectifs

Comprendre les trois classes du package java.util.regex. Construire des expressions régulières avec les métacaractères Java. Utiliser Pattern, Matcher et leurs méthodes pour rechercher, valider et remplacer du texte.

  Un peu d'histoire

Les expressions régulières (regex) ont été inventées par le mathématicien Stephen Kleene dans les années 1950. Elles ont été popularisées par les outils Unix (grep, sed, awk) et sont aujourd'hui disponibles dans tous les langages modernes. Java les intègre nativement via le package java.util.regex depuis Java 1.4.

1. Architecture du package java.util.regex

Définition — Expression régulière Une expression régulière (regex ou regexp) est une séquence de caractères formant un motif (pattern) utilisé pour rechercher, valider ou manipuler des chaînes de caractères selon des règles syntaxiques précises.

Le package java.util.regex repose sur trois classes principales :

Classe Rôle Création
Pattern Représentation compilée d'une expression régulière Pattern.compile(regex) — pas de constructeur public
Matcher Moteur qui applique le Pattern à une chaîne cible pattern.matcher(texte) — pas de constructeur public
PatternSyntaxException Exception levée si la syntaxe du Pattern est invalide Levée automatiquement par Pattern.compile()
   
Workflow standard d'utilisation Java
import java.util.regex.Pattern;
import java.util.regex.Matcher;

String regex  = "motif";
String texte  = "texte à analyser";

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(texte);

if (matcher.find()) {
    System.out.println("Trouvé !");
}

2. Syntaxe des expressions régulières

2.1 Ancres et positions

Expression Correspondance Exemple
^ Début de ligne ^Bonjour → la ligne commence par "Bonjour"
$ Fin de ligne monde$ → la ligne se termine par "monde"
\A Début de la chaîne entière Indépendant du mode multiligne
\z Fin absolue de la chaîne Aucune nouvelle ligne finale tolérée
\b Frontière de mot \bdev\b → "dev" entier, pas "developpement"
\B Non-frontière de mot \Bdev\B → "dev" au milieu d'un mot

2.2 Classes de caractères

Expression Correspondance Équivalent
. N'importe quel caractère sauf saut de ligne
[abc] Un caractère parmi a, b ou c
[^abc] Tout caractère sauf a, b, c
[a-z] Une lettre minuscule de a à z
[A-Z0-9] Lettre majuscule ou chiffre
\d Un chiffre [0-9]
\D Un non-chiffre [^0-9]
\w Un caractère alphanumérique ou _ [a-zA-Z0-9_]
\W Un caractère non alphanumérique [^a-zA-Z0-9_]
\s Un espace blanc (espace, tab, saut de ligne…) [\t\n\r\f ]
\S Un caractère non-espace

2.3 Quantificateurs

Quantificateur Signification Exemple
* 0 ou plusieurs occurrences ab* → "a", "ab", "abb", "abbb"…
+ 1 ou plusieurs occurrences ab+ → "ab", "abb", "abbb"…
? 0 ou 1 occurrence colou?r → "color" ou "colour"
{n} Exactement n occurrences \d{4} → exactement 4 chiffres
{n,} Au moins n occurrences \d{2,} → 2 chiffres ou plus
{n,m} Entre n et m occurrences \d{2,4} → 2 à 4 chiffres

2.4 Groupes et alternance

Expression Signification
(re) Groupe capturant — mémorise le texte correspondant
(?:re) Groupe non capturant — regroupe sans mémoriser
a|b Alternance — correspond à a ou b

2.5 Échappement des métacaractères

Double échappement en Java En Java, la barre oblique inverse \ est un caractère d'échappement dans les chaînes String. Pour représenter \d dans une regex Java, il faut écrire "\\d" — la première barre échappe la seconde pour la chaîne, et la paire \\ produit un seul \ transmis au moteur regex.
String regex = "\\d+";     // regex : \d+  (un ou plusieurs chiffres)
String regex = "\\bdev\\b"; // regex : \bdev\b (mot entier "dev")
String regex = "\\.com";    // regex : \.com  (point littéral + "com")

3. La classe Pattern

Pattern Pattern est la représentation compilée d'une expression régulière. La compilation est coûteuse — si vous réutilisez le même pattern, compilez-le une seule fois et réutilisez l'objet Pattern.
Pattern p1 = Pattern.compile("\\d+");

Pattern p2 = Pattern.compile("^[A-Z]", Pattern.CASE_INSENSITIVE);

Pattern p3 = Pattern.compile(
    "^[a-zA-Z0-9._%+-]+" +
    "@[a-zA-Z0-9.-]+" +
    "\\.[a-zA-Z]{2,}$"
);

boolean valide = p3.matcher("user@example.com").matches();
System.out.println("Email valide : " + valide);
Sortie
Email valide : true

4. La classe Matcher et ses méthodes

4.1 Méthodes d'étude (recherche)

Méthode Description Point de départ
find() Cherche la prochaine sous-séquence correspondant au motif Après la dernière correspondance (ou 0)
find(int start) Cherche à partir de l'indice start Position spécifiée
matches() Vérifie si toute la chaîne correspond au motif Début de la chaîne
lookingAt() Vérifie si le début de la chaîne correspond au motif Début de la chaîne

4.2 Méthodes d'indexation

Méthode Description
start() Indice de début de la dernière correspondance
end() Indice (exclu) de fin de la dernière correspondance
start(int group) Indice de début du groupe capturant numéro group
end(int group) Indice de fin du groupe capturant numéro group
group() Texte de la dernière correspondance complète (groupe 0)
group(int n) Texte capturé par le groupe numéro n
groupCount() Nombre de groupes capturants dans le pattern

4.3 Méthodes de remplacement

Méthode Description
replaceAll(String remplacement) Remplace toutes les occurrences correspondantes
replaceFirst(String remplacement) Remplace uniquement la première occurrence
appendReplacement(StringBuffer sb, String r) Remplacement incrémental — étape intermédiaire
appendTail(StringBuffer sb) Ajoute le reste de la chaîne après le dernier remplacement

5. Groupes de capture

Groupe de capture Un groupe de capture est délimité par des parenthèses () dans le pattern. Il mémorise la portion de texte qui correspond à la partie du motif entre ces parenthèses. Les groupes sont numérotés de gauche à droite en comptant les parenthèses ouvrantes. Le groupe 0 représente toujours la correspondance entière.

  Exemple 1 — Groupes de capture

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TestGroupes {
    public static void main(String[] args) {
        String line    = "www.developpement123.com";
        String pattern = "(.*)([0-9]+)(.*)";

        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(line);

        System.out.println("Nombre de groupes : " + m.groupCount());
        if (m.find()) {
            System.out.println("Groupe 0 (tout) : " + m.group(0));
            System.out.println("Groupe 1 (.*)   : " + m.group(1));
            System.out.println("Groupe 2 ([0-9]+): " + m.group(2));
            System.out.println("Groupe 3 (.*)   : " + m.group(3));
        }
    }
}
Sortie
Nombre de groupes : 3
Groupe 0 (tout)  : www.developpement123.com
Groupe 1 (.*)    : www.developpement12
Groupe 2 ([0-9]+): 3
Groupe 3 (.*)    : .com
Comportement glouton de .* Le quantificateur .* est glouton : il capture autant de caractères que possible. C'est pourquoi le groupe 1 capture "www.developpement12" et non "www.developpement" — il laisse le minimum possible au groupe 2. Pour un comportement non glouton (paresseux), utilisez .*?.

6. Exemples pratiques

  Exemple 2 — Trouver toutes les occurrences d'un motif

import java.util.regex.*;

Pattern pattern = Pattern.compile("dev");
Matcher m = pattern.matcher("info-dev : www.developpement-informatique.com");

while (m.find()) {
    System.out.println("Motif trouvé de " + m.start() + " à " + (m.end() - 1));
}
Sortie
Motif trouvé de 5 à 7
Motif trouvé de 15 à 17

  Exemple 3 — Mots entiers avec \b

Pattern pattern = Pattern.compile("\\bdev\\b");
Matcher m = pattern.matcher("info dev : www.developpement-informatique.com");

int cpt = 0;
while (m.find()) {
    cpt++;
    System.out.println("Mot " + cpt + " : indice " + m.start() + " à " + (m.end() - 1));
}
System.out.println("Total : " + cpt + " occurrence(s)");
Sortie
Mot 1 : indice 5 à 7
Total : 1 occurrence(s)

  Exemple 4 — matches() vs lookingAt() vs find()

Pattern pattern = Pattern.compile("dev");
Matcher matcher = pattern.matcher("developpement-informatique.com");

System.out.println("find()      : " + matcher.find());
matcher.reset();
System.out.println("lookingAt() : " + matcher.lookingAt());
matcher.reset();
System.out.println("matches()   : " + matcher.matches());
Sortie
find()      : true  (trouve "dev" n'importe où)
lookingAt() : true  (la chaîne COMMENCE par "dev")
matches()   : false (la chaîne entière n'est PAS "dev")

  Exemple 5 — replaceAll() et replaceFirst()

Pattern pattern = Pattern.compile("dev");
Matcher matcher = pattern.matcher("info-dev, dev-info, dev");

String remplaceAll    = matcher.replaceAll("soft");
System.out.println("replaceAll    : " + remplaceAll);

matcher.reset();
String remplaceFirst  = matcher.replaceFirst("soft");
System.out.println("replaceFirst  : " + remplaceFirst);
Sortie
replaceAll    : info-soft, soft-info, soft
replaceFirst  : info-soft, dev-info, dev

  Exemple 6 — appendReplacement / appendTail

Pattern pattern = Pattern.compile("dev");
Matcher matcher = pattern.matcher("info-dev, dev-info");

StringBuffer resultat = new StringBuffer();
while (matcher.find()) {
    matcher.appendReplacement(resultat, "soft");
}
matcher.appendTail(resultat);
System.out.println(resultat);
Sortie
info-soft, soft-info

7. Gestion des erreurs — PatternSyntaxException

PatternSyntaxException Exception non contrôlée levée par Pattern.compile() si la syntaxe de l'expression régulière est invalide. Ses méthodes permettent de diagnostiquer l'erreur.
Méthode Description
getDescription() Description textuelle de l'erreur
getIndex() Position dans le pattern où l'erreur se produit
getPattern() Le pattern erroné
getMessage() Message complet avec description, indice et visualisation
import java.util.regex.*;

try {
    Pattern p = Pattern.compile("[chiffre invalide");
} catch (PatternSyntaxException e) {
    System.out.println("Erreur dans le pattern !");
    System.out.println("Description : " + e.getDescription());
    System.out.println("Indice      : " + e.getIndex());
    System.out.println("Pattern     : " + e.getPattern());
}
Sortie
Erreur dans le pattern !
Description : Unclosed character class
Indice      : 0
Pattern     : [chiffre invalide

8. Patterns de validation courants

  Complément — Regex utiles en pratique

Cas d'usage Expression régulière
Entier positif ^\d+$
Nombre décimal ^\d+(\.\d+)?$
Adresse email (simplifiée) ^[\w._%+-]+@[\w.-]+\.[a-zA-Z]{2,}$
Numéro de téléphone marocain ^0[5-7]\d{8}$
Code postal (5 chiffres) ^\d{5}$
URL http/https (simplifiée) ^https?://[\w.-]+\.[a-z]{2,}
Mot de passe (8+ car., maj., chiffre) ^(?=.*[A-Z])(?=.*\d).{8,}$
Date JJ/MM/AAAA ^\d{2}/\d{2}/\d{4}$

9. Exercice

Validateur et extracteur de données

Niveau : Intermédiaire

Écrire un programme Java qui effectue trois tâches distinctes avec les expressions régulières.

Travail demandé

  1. Validation d'email : écrire une méthode static boolean validerEmail(String email) qui utilise matches() pour valider une adresse email avec le pattern ^[\w._%+-]+@[\w.-]+\.[a-zA-Z]{2,}$.
  2. Extraction de nombres : écrire une méthode static void extraireNombres(String texte) qui utilise find() en boucle pour trouver et afficher tous les nombres entiers dans une chaîne.
  3. Nettoyage de texte : écrire une méthode static String nettoyerEspaces(String texte) qui remplace toute séquence d'espaces multiples par un seul espace avec replaceAll().
Sortie attendue
Sortie
=== Validation emails ===
mostafa@um6p.ma       : valide
contact@.invalid      : invalide
user.name+tag@site.fr : valide
@nodomain.com         : invalide

=== Extraction de nombres ===
Texte : "Java 21 sort en 2023 avec 15 nouvelles fonctionnalités"
Nombres trouvés : 21, 2023, 15

=== Nettoyage d'espaces ===
Avant : "Java   est   un   langage"
Après : "Java est un langage"

  L'essentiel en bref

Le package java.util.regex expose trois classes : Pattern (motif compilé créé via Pattern.compile()), Matcher (moteur de correspondance créé via pattern.matcher(texte)), et PatternSyntaxException (erreur de syntaxe dans le pattern). Les méthodes clés du Matcher sont find() pour rechercher la prochaine occurrence, matches() pour valider toute la chaîne, lookingAt() pour vérifier le début, replaceAll() et replaceFirst() pour substituer du texte, et group(n) pour extraire les groupes capturants. En Java, chaque \ regex s'écrit \\ dans une chaîne Java — toujours doubler les barres obliques inverses. Compilez vos Pattern une seule fois (constante static final) si vous les réutilisez fréquemment.

Sortie
// La sortie apparaîtra ici…
Prêt · Ctrl+Entrée pour exécuter

Discussion (0)

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Votre commentaire sera visible après modération.