Menu
Français

Regex en JavaScript : test, match, replace et groupes

Comment utiliser les expressions régulières en JavaScript : création du motif, méthodes essentielles (test, match, replace), flags et groupes de capture, avec des exemples concrets.

Une regex, c'est un motif pour retrouver du texte

Une expression régulière javascript décrit la forme d'une chaîne : « quatre chiffres », « un mot suivi d'une virgule », « quelque chose qui ressemble à un email ». En JavaScript, vous avez deux façons d'en créer une :

index.js
Output
Click Run to see the output here.

La forme littérale — des slashs autour du motif, les flags après le slash de fermeture — c'est celle que tu utiliseras dans la plupart des cas. Passe à new RegExp(...) quand le motif lui-même est dynamique, par exemple lorsqu'il est construit à partir d'une saisie utilisateur ou d'une variable.

Le i à la fin est un flag. i signifie insensible à la casse. On reviendra sur les flags dans un instant.

test : est-ce que ça matche ?

La question la plus simple qu'on puisse poser à une expression régulière javascript, c'est « est-ce que cette chaîne contient une correspondance ? ». C'est exactement le rôle de test :

index.js
Output
Click Run to see the output here.

\d désigne « n'importe quel chiffre ». test renvoie uniquement true ou false, rien d'autre. Quand tu as juste besoin d'une réponse par oui ou par non — valider un champ, filtrer un tableau — test est l'outil parfait.

match : récupérer le texte correspondant

Quand c'est le texte capturé qui t'intéresse, utilise la méthode match des chaînes :

index.js
Output
Click Run to see the output here.

Sans le flag g, match renvoie un tableau contenant la première correspondance accompagnée de métadonnées (index, input). Avec le flag g, on récupère simplement un tableau de chaînes listant toutes les occurrences. Et attention : quand rien ne correspond, le retour est null — pas un tableau vide — donc pensez à vous protéger :

index.js
Output
Click Run to see the output here.

Les flags modifient le comportement du pattern

Les flags se placent juste après le slash fermant et ajustent la manière dont s'effectue la recherche. Voici ceux que tu utiliseras le plus souvent :

  • g — global, récupère toutes les occurrences au lieu de s'arrêter à la première.
  • i — insensible à la casse.
  • m — multiligne : ^ et $ correspondent alors au début et à la fin de chaque ligne, et non plus seulement à ceux de la chaîne.
  • s — dotall, qui permet à . de matcher aussi les sauts de ligne.
  • u — prise en charge Unicode, indispensable pour beaucoup d'emojis et de caractères non-ASCII.
index.js
Output
Click Run to see the output here.

Sans le flag m, ^ s'ancre uniquement au tout début de la chaîne. Avec m, il s'ancre au début de chaque ligne, ce qui permet de capturer à la fois Roses et Violets.

Classes de caractères et quantificateurs

Voici les briques de base que l'on retrouve dans la plupart des expressions régulières :

  • \d un chiffre, \w un caractère de mot (lettre, chiffre ou underscore), \s un espace blanc.
  • [abc] l'un des caractères a, b ou c. [^abc] tout sauf ces caractères. [a-z] une plage.
  • . n'importe quel caractère sauf un saut de ligne.
  • * zéro ou plus, + un ou plus, ? zéro ou un.
  • {3} exactement trois, {2,5} entre deux et cinq, {2,} deux ou plus.
  • ^ début, $ fin.

Tout ça mis bout à bout :

index.js
Output
Click Run to see the output here.

\b marque une frontière de mot — cette ligne invisible entre un caractère de mot et un caractère qui n'en est pas un. Pratique quand tu veux capturer un mot entier et rien d'autre.

Les groupes de capture : mémoriser des bouts du match

Les parenthèses créent un groupe qui capture ce qu'il a trouvé. exec et match te renvoient ces captures en plus du résultat global :

index.js
Output
Click Run to see the output here.

L'indice 0 correspond à la correspondance complète, puis chaque groupe occupe sa propre case à la suite. Compter les groupes par position devient vite pénible dès qu'on en a plus de deux — autant les nommer :

index.js
Output
Click Run to see the output here.

Les groupes nommés sont plus lisibles à l'usage et résistent au réordonnancement du motif.

replace : réécrire le texte capturé

replace prend un motif et une valeur de remplacement. Ce remplacement peut être une chaîne ou bien une fonction :

index.js
Output
Click Run to see the output here.

Sans le flag g, seule la première occurrence est remplacée. C'est une erreur classique : on oublie le flag et on se demande pourquoi le deuxième e-mail reste tel quel.

Les chaînes de remplacement acceptent aussi des références arrière. $1, $2, etc. renvoient aux groupes de capture, et $<nom> aux groupes nommés :

index.js
Output
Click Run to see the output here.

Pour tout ce qui va au-delà d'une simple substitution, passez une fonction. Celle-ci reçoit la correspondance et les groupes capturés en arguments :

index.js
Output
Click Run to see the output here.

Le tiret bas correspond au match complet (dont on n'a pas besoin), et n représente le premier groupe de capture. Ce combo — regex plus fonction de remplacement — couvre la majorité des manipulations de texte qu'on rencontre en vrai.

matchAll : tous les résultats avec leurs groupes

String.prototype.matchAll renvoie un itérateur sur chaque occurrence trouvée, avec ses groupes de capture — chose impossible avec un simple match accompagné du flag g :

index.js
Output
Click Run to see the output here.

matchAll exige le flag g. Sans lui, tu te prends un TypeError. Si tu veux un accès aléatoire plutôt qu'une simple itération, éclate le résultat dans un tableau avec [...text.matchAll(email)].

Échapper les caractères spéciaux

Certains caractères comme . * + ? ( ) [ ] { } | \ ^ $ ont une signification particulière dans une expression régulière JavaScript. Pour les faire correspondre littéralement, il faut les échapper avec un antislash :

index.js
Output
Click Run to see the output here.

La version sans échappement accepte aussi examplexcom parce que . veut dire « n'importe quel caractère ». Ce genre de bug est fréquent — et silencieux. Quand une regex matche trop de choses, le premier réflexe, c'est de chercher un . qui n'a pas été échappé.

Si vous construisez un pattern à partir d'une saisie utilisateur, vous devez l'échapper, sinon l'utilisateur peut injecter de la syntaxe regex :

index.js
Output
Click Run to see the output here.

$& dans une chaîne de remplacement, c'est le raccourci qui représente « toute la correspondance ».

Lookahead et lookbehind

Il arrive qu'on veuille capturer du texte uniquement s'il est suivi (ou précédé) de quelque chose de précis — sans pour autant inclure ce quelque chose dans la correspondance. C'est précisément le rôle des lookarounds :

index.js
Output
Click Run to see the output here.
  • (?= ...) : assertion avant positive, autrement dit « suivi de ».
  • (?<= ...) : assertion arrière positive, autrement dit « précédé de ».
  • (?! ...) et (?<! ...) sont les versions négatives.

Les assertions (lookarounds) ne consomment aucun caractère : ce que vous « regardez » reste disponible pour la suite du motif.

Petit mot sur la validation d'e-mails

C'est une question qui revient tout le temps : « donne-moi une regex qui valide les e-mails ». Ma réponse honnête : évitez. La vraie grammaire des e-mails est tordue, et toute regex assez courte pour être lisible se plantera d'un côté ou de l'autre. Pour valider un champ de formulaire, un motif pragmatique fait largement l'affaire :

index.js
Output
Click Run to see the output here.

Lisez ça comme : « des caractères non blancs et différents de @, un @, la même chose, un point, encore la même chose. » Ça attrape les fautes de frappe évidentes sans prétendre respecter la RFC 5322. Pour une vraie vérification, envoyez un e-mail de confirmation.

Pièges classiques

Quelques pièges à bien avoir en tête :

  • Oublier le flag g avec replace ou matchAll. Vous n'obtiendrez que la première occurrence, ou carrément un TypeError.
  • Le lastIndex persistant des regex globales. Une regex avec le flag g ou y retient où elle s'est arrêtée entre deux appels à test ou exec. Ne la réutilisez pas sur des chaînes sans rapport — créez-en une nouvelle, ou passez par matchAll.
  • Points et slashes non échappés dans les motifs dynamiques. Échappez toujours l'entrée utilisateur avant de la balancer dans new RegExp(...).
  • Le backtracking catastrophique. Des quantificateurs imbriqués comme (a+)+ sur une entrée piégeuse peuvent geler un onglet entier. Si une regex vous paraît lente, simplifiez-la.

Et ensuite : les dates et les heures

Les regex gèrent la forme du texte ; les vraies données arrivent aussi avec des dates et des heures qu'il faut parser, formater et manipuler. La page suivante couvre Date, Intl.DateTimeFormat, et le modèle mental qui vous évitera les bugs de fuseaux horaires.

Questions fréquentes

Comment créer une regex en JavaScript ?

Deux options. La forme littérale, entre slashes : /hello/i. Le constructeur, qui prend une chaîne : new RegExp('hello', 'i'). On préfère la forme littérale quand le motif est fixe, et le constructeur quand il faut construire le motif dynamiquement à partir d'une variable.

Quelle différence entre test, match et exec ?

regex.test(str) renvoie un booléen — c'est le plus rapide quand on veut juste savoir s'il y a une correspondance. str.match(regex) renvoie un tableau de résultats (ou null). regex.exec(str) renvoie une correspondance à la fois avec les groupes de capture, et avec le flag g il garde la position entre les appels grâce à lastIndex.

Comment remplacer toutes les occurrences avec une regex ?

Il faut le flag g : str.replace(/foo/g, 'bar'). Sans g, seule la première occurrence est remplacée. On peut aussi utiliser str.replaceAll(/foo/g, 'bar') — mais attention, replaceAll avec une regex exige le flag g, sinon ça lève une exception.

À quoi servent les groupes de capture ?

Les parenthèses dans un motif créent des groupes de capture qui mémorisent ce qui a été matché. /(\d{4})-(\d{2})/.exec('2024-11') renvoie un tableau où l'index 1 vaut '2024' et l'index 2 vaut '11'. On peut aussi les nommer avec (?<year>\d{4}) et y accéder via match.groups.year.

Apprendre à coder avec Coddy

COMMENCER