Les expressions régulières (regex) ont une réputation de hiéroglyphes, et c'est mérité quand on les découvre sur une ligne de 80 caractères. Pourtant, une dizaine de briques suffisent à résoudre l'essentiel : valider un format, extraire des morceaux de texte, nettoyer des données, faire un « rechercher-remplacer » intelligent. Ce guide les présente dans l'ordre, avec des exemples testés, les pièges propres au français (accents, espaces insécables) et le risque de performance qu'on ignore trop souvent.
Testez chaque motif dans le testeur de regex, qui surligne les correspondances et affiche les groupes capturés. Il est utile aussi avec le générateur de slug et l'encodeur d'URL.
Les briques de base
Une regex s'écrit entre barres obliques, suivie de drapeaux : /motif/gi. Dix éléments couvrent la majorité des besoins :
| Élément | Signification | Exemple |
|---|---|---|
. | N'importe quel caractère sauf un retour à la ligne | c.t : cat, c7t |
\d, \w, \s | Chiffre ; lettre non accentuée, chiffre ou _ ; espace | \d\d : 42 |
[abc], [^abc], [a-z] | Un caractère parmi, hors de, dans un intervalle | [aeiou] |
^, $ | Début, fin du texte (de la ligne avec m) | ^\d+$ |
*, +, ? | 0 ou plus, 1 ou plus, 0 ou 1 | colou?r |
{n}, {n,m} | Exactement n, de n à m répétitions | \d{2,4} |
(…), (?:…) | Groupe capturant, non capturant | (\d+)€ |
a|b | Alternative | jour|nuit |
(?=…), (?<=…) | Suivi de, précédé de (sans consommer) | \d+(?=€) |
\b | Frontière de mot | \bchat\b |
Pour écrire littéralement un caractère spécial (. * + ? ( ) [ ] { } ^ $ | \), faites-le précéder d'une barre oblique inverse : \. désigne un vrai point. Les drapeaux principaux : g (toutes les correspondances), i (insensible à la casse), m (^ et $ par ligne), u (Unicode) et s (le point reconnaît aussi les retours à la ligne).
Gourmand ou paresseux
Les quantificateurs sont par défaut gourmands : ils prennent le plus de texte possible. Ajouter un point d'interrogation (*?, +?) les rend paresseux : ils s'arrêtent dès que le motif est satisfait.
Sur <b>gras</b> et <i>italique</i> : <.+> (gourmand) trouve une seule correspondance, tout le texte ; <.+?> (paresseux) en trouve quatre, une par balise. Une alternative plus précise encore est <[^>]+> : « tout sauf > ».
Règle d'or : préférez une classe négative précise ([^"]* pour « tout jusqu'au prochain guillemet ») à un point paresseux. C'est plus rapide, plus lisible et moins fragile.
Six motifs courants, testés
| Usage | Motif | Accepte / refuse |
|---|---|---|
| Téléphone français | ^(?:(?:\+|00)33|0)\s?[1-9](?:[\s.-]?\d{2}){4}$ | 06 12 34 56 78, +33 6 12 34 56 78, 01.23.45.67.89 / 06 12 34 56 |
| Code postal | ^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$ | 75001, 20000 / 00123, 1234 |
| Date jj/mm/aaaa | ^(0[1-9]|[12]\d|3[01])\/(0[1-9]|1[0-2])\/\d{4}$ | 15/08/2026 / 32/01/2026 (mais accepte 31/02) |
| Couleur hexadécimale | ^#(?:[0-9a-fA-F]{3}){1,2}$ | #fff, #c67139 / #ff, #12345g |
| Mot répété (français) | (?<!\p{L})(\p{L}+)\s+\1(?!\p{L}) avec le drapeau u | « le le chat », « Il a a faim » |
| Prix en euros | \d+(?:[.,]\d{1,2})?\s?€ avec g | 12,50 €, 8€, 3.5 € |
Ces motifs vérifient une forme, pas une validité : « 31/02/2026 » a la forme d'une date et pas celle d'un jour du calendrier ; un code postal à cinq chiffres peut ne correspondre à aucune commune. Pour une adresse e-mail, la seule vérification fiable est d'envoyer un message de confirmation : une regex ne peut pas savoir si la boîte existe.
Le français et les regex : accents, espaces, apostrophes
\wet\bignorent les accents.\w+coupe « été » après le « t » initial, et\bété\bne trouve rien. Utilisez\p{L}avec le drapeauupour les lettres, et des assertions à la place de\b:(?<!\p{L})été(?!\p{L}).- Les espaces insécables.
\sreconnaît l'espace insécable (U+00A0) et l'espace fine insécable (U+202F) qui précèdent « ; : ! ? » dans la typographie française. Une espace saisie[ ]ne les trouve pas. - L'apostrophe peut être droite (
') ou typographique (’) : couvrez les deux avecl['’]. - Majuscules accentuées : le drapeau
ifait correspondre « é » et « É » ;\p{Lu}reconnaît toute majuscule.
Utiliser une regex en JavaScript
re.test(texte)renvoie vrai ou faux ;texte.match(re)donne la première correspondance (ou toutes avecg) ;texte.matchAll(re)les parcourt avec leurs groupes ;texte.replace(re, remplacement)transforme le texte.- Le piège du drapeau
gavectest(). Une regex globale mémorise sa position :const re = /a/g; re.test('a')donnetrue, puis le même appel redonnefalse. N'utilisez pasgpour un simple test, ou recréez la regex. - Les groupes nommés rendent le code lisible :
(?<jour>\d{2})se relit avecm.groups.jour; dans un remplacement, on les rappelle avec$<jour>. Exemple :'2026-10-10'.replace(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/, '$<d>/$<m>/$<y>')donne « 10/10/2026 ». - Dans une chaîne, la barre oblique inverse doit être doublée :
new RegExp("\\d+"). La notation littérale/\d+/évite cette contrainte.
Le piège des performances : le backtracking catastrophique
Pour trouver une correspondance, le moteur essaie des possibilités et revient en arrière quand l'une échoue. Avec des quantificateurs imbriqués comme ^(a+)+$, le nombre d'essais double à chaque caractère supplémentaire quand la correspondance échoue : quelques dizaines de caractères suffisent à figer un programme. C'est le ReDoS (déni de service par expression régulière).
- En 2019, une règle de pare-feu mal écrite a épuisé les processeurs de Cloudflare et provoqué une panne mondiale d'environ 27 minutes ; le fournisseur a adopté depuis un moteur sans backtracking.
- Évitez les quantificateurs imbriqués sur des éléments qui peuvent se recouvrir (
(a+)+,(.*)*,(\w+\s?)*), préférez des classes précises, et limitez la longueur du texte soumis à la regex. - Côté serveur, face à des données de tiers, envisagez un moteur à temps linéaire (comme RE2).
Méthode. Écrivez d'abord le motif sur 3 à 5 exemples qui doivent correspondre et 3 à 5 qui ne doivent pas. Ajoutez des cas limites (vide, très long, accents). Gardez ces exemples en commentaire : une regex sans exemples est impossible à maintenir.
Questions fréquentes
Que signifie le drapeau g dans une regex ?
Le drapeau « g » (global) fait trouver toutes les correspondances au lieu de s'arrêter à la première. Attention : avec la méthode test(), une regex globale mémorise sa position et peut donner des résultats alternés.
Quelle est la différence entre .* et .*? ?
.* est gourmand : il prend le plus de caractères possible. .*? est paresseux : il s'arrête dès que le reste du motif est satisfait. Sur « <b>a</b><b>b</b> », <.+> trouve tout, <.+?> trouve chaque balise.
Pourquoi \w ne reconnaît-il pas les lettres accentuées ?
Parce que \w se limite à [A-Za-z0-9_]. Pour des lettres de toutes langues, utilisez \p{L} avec le drapeau u, ou une classe explicite comme [a-zA-ZÀ-ÿ].
Peut-on valider une adresse e-mail avec une regex ?
Seulement sa forme. La norme est trop permissive pour une regex raisonnable, et une adresse de bonne forme peut ne pas exister. La vérification fiable consiste à envoyer un message de confirmation.
Qu'est-ce que le ReDoS ?
Un déni de service provoqué par une expression régulière dont le backtracking explose sur certaines entrées. Il se prévient en évitant les quantificateurs imbriqués ambigus, en limitant la taille des entrées et en testant les motifs avec des textes volontairement difficiles.