W3docs

Groupes et captures dans les regex Java

Capturez des parties de texte en Java avec les parenthèses, les groupes numérotés et les groupes nommés dans les expressions régulières.

Une expression régulière ne se contente pas de vous dire si une chaîne correspond — elle peut découper la correspondance en morceaux que vous pouvez relire. Ces morceaux sont des groupes. En encadrant une partie du motif dans des parenthèses, vous créez un groupe capturant, et une fois qu'un Matcher réussit, vous extrayez chaque groupe par numéro ou par nom. Ce chapitre couvre les groupes numérotés, les groupes nommés, les rétéférences, les groupes non capturants, et comment tout cela s'intègre dans les remplacements.

Groupes capturants numérotés

Chaque paire de parenthèses dans un motif ouvre un groupe capturant, numéroté de gauche à droite par leur ( d'ouverture. Le groupe 0 est spécial : c'est toujours la correspondance entière. Ainsi, (\d{4})-(\d{2})-(\d{2}) vous donne quatre groupes — la date complète plus l'année, le mois et le jour.

Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2026-05-30");
if (m.matches()) {
    System.out.println(m.group(0)); // 2026-05-30 (entire match)
    System.out.println(m.group(1)); // 2026
    System.out.println(m.group(2)); // 05
    System.out.println(m.group(3)); // 30
}

groupCount() retourne le nombre de groupes capturants sans compter le groupe 0, donc le motif ci-dessus rapporte 3. La lecture d'un indice de groupe inexistant lève une IndexOutOfBoundsException.

Groupes nommés

Compter les parenthèses devient fragile à mesure que les motifs grandissent. Les groupes nommés, écrits (?<name>...), permettent de lire une capture par un libellé lisible plutôt que par un indice. Les noms doivent être des identifiants Java valides et uniques dans le motif.

Pattern p = Pattern.compile("(?<user>[\\w.]+)@(?<host>[\\w.]+)");
Matcher m = p.matcher("[email protected]");
if (m.matches()) {
    System.out.println(m.group("user")); // ada
    System.out.println(m.group("host")); // math.org
}

Les groupes nommés sont toujours numérotés en dessous, donc m.group(1) et m.group("user") retournent le même texte. Le nom est purement pour votre lisibilité.

Rétéférences

Une rétéférence correspond au même texte qu'un groupe précédent a déjà capturé. À l'intérieur du motif, vous écrivez \1 pour le groupe 1 (ou \k<name> pour un groupe nommé). C'est ainsi que vous détectez une répétition — par exemple, un mot doublé — au sein d'une seule correspondance.

// \b(\w+)\s+\1\b  matches a word followed by the same word again
Pattern p = Pattern.compile("\\b(\\w+)\\s+\\1\\b");
Matcher m = p.matcher("the the end");
if (m.find()) {
    System.out.println(m.group(1)); // the
}

Notez le double antislash dans le source Java : \\1 dans la chaîne devient \1 dans la regex réelle. Une rétéférence ne peut correspondre qu'après que son groupe a capturé, donc le groupe doit apparaître plus tôt dans le motif.

Captures dans les remplacements

String.replaceAll, Matcher.replaceAll et appendReplacement comprennent tous les références de groupe dans le texte de remplacement. Utilisez $1, $2, ... pour les groupes numérotés et ${name} pour les groupes nommés. Cela transforme les regex en un petit outil de réordonnancement et de création de modèles.

RéférenceSignification dans le remplacement
$0La correspondance entière
$1, $2, ...Groupes capturants numérotés
${name}Un groupe capturant nommé
\$Un signe dollar littéral
// Reorder "First Last" into "Last, First"
String out = "Ada Lovelace".replaceAll("(\\w+)\\s+(\\w+)", "$2, $1");
System.out.println(out); // Lovelace, Ada

Si vous avez besoin d'un $ ou \ littéral dans la sortie, échappez-le avec \\$ ou \\\\ dans la chaîne Java.

Groupes non capturants

Parfois, vous avez besoin de parenthèses uniquement pour grouper une alternance ou appliquer un quantificateur — sans capturer. Un groupe non capturant (?:...) fait exactement cela : il groupe sans consommer de numéro de groupe, ce qui maintient vos indices propres et rend le moteur légèrement plus rapide.

// Group the protocol alternation, but capture only the host
Pattern p = Pattern.compile("(?:https?|ftp)://(\\S+)");
Matcher m = p.matcher("https://w3docs.com");
if (m.find()) {
    System.out.println(m.group(1)); // w3docs.com  (group 1, not 2)
}

Comme (?:https?|ftp) est non capturant, l'hôte est le groupe 1 plutôt que le groupe 2. Un groupe capturant optionnel qui ne participe pas à la correspondance retourne null, donc vérifiez toujours la nullité des groupes optionnels avant de les utiliser.

Un exemple exécutable

Le programme ci-dessous utilise chaque type de groupe en une seule exécution : des parties de date numérotées, des champs d'email nommés, une rétéférence de mot doublé, des références de groupe dans deux remplacements, un groupe de protocole non capturant, et un groupe optionnel qui revient à null.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • Les deux lignes de date montrent les groupes numérotés : group(0) est la correspondance entière, tandis que group(1..3) correspondent à l'année, au mois et au jour capturés par position.
  • La ligne email prouve que les groupes nommés lisent le même texte que les indices, et groupCount=2 ne compte que les captures nommées, jamais le groupe 0.
  • Doubled: the et Doubled: sat proviennent de la rétéférence \1 qui correspond à ce que le groupe de mot vient de capturer — chaque mot répété est trouvé indépendamment.
  • Swapped: Lovelace, Ada, Turing, Alan montre $2, $1 réordonnant chaque paire de noms, tandis que Masked: card [4111] [2222] montre la référence nommée ${num} formatant la sortie.
  • Le (?:https?|ftp) non capturant maintient l'hôte au groupe 1 (w3docs.com), et le groupe de fraction optionnel affiche frac=null car il n'a jamais participé à la correspondance de 42.

Et ensuite

Les groupes s'appuient sur le reste du moteur regex, il est donc utile de maîtriser les éléments environnants :

Pratique

Pratique
Dans le motif (?:https?|ftp)://(\S+), quel groupe contient la partie hôte capturée par (\S+) ?
Dans le motif (?:https?|ftp)://(\S+), quel groupe contient la partie hôte capturée par (\S+) ?
Was this page helpful?