10 - Les regex en JavaScript
Ce que tu vas apprendre
- Creer une regex : literal
/pattern/vs constructeurRegExp - Les méthodes
.test(),.match(),.matchAll(),.replace(),.replaceAll(),.search(),.split() - Quand utiliser quelle méthode
- Le bug du
lastIndexavec le flagg
Prerequisites
Tu connais maintenant la syntaxe des regex. Mais une regex sans les méthodes JavaScript qui l'accompagnent, c'est comme un couteau sans manche. Cet article passe en revue toutes les manières d'utiliser une regex en JS, avec les gotchas que j'ai rencontres au fil des annees.
Creer une regex
Deux manières :
javascript// Literal - evalue au parsing
const regex1 = /\d{3}-\d{4}/g;
// Constructeur - evalue a l'execution
const regex2 = new RegExp("\\d{3}-\\d{4}", "g");
Le literal est préférable dans 90% des cas. Il est plus lisible et le moteur peut l'optimiser au parsing. Le constructeur sert quand le pattern est dynamique :
javascriptfunction findWord(text, word) {
// Le pattern vient d'une variable, il faut le constructeur
const regex = new RegExp(`\\b${word}\\b`, "gi");
return text.match(regex);
}
Attention : avec le constructeur, les backslashes doivent etre doubles. \d dans un literal devient "\\d" dans une string. C'est une source d'erreurs frequente.
javascript// Piege classique
new RegExp("\d+"); // Matche "d+" (le \d n'est pas echappe)
new RegExp("\\d+"); // Matche des chiffres (correct)
Et si le pattern vient de l'utilisateur, echappe les caractères speciaux :
javascriptfunction escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\{{body}}amp;");
}
const userInput = "prix (TTC)";
const safe = new RegExp(escapeRegex(userInput), "g");
// Matche litteralement "prix (TTC)" sans interpreter les parentheses
.test() - Le booleen
Renvoie true ou false. La méthode la plus rapide si tu veux juste savoir si un pattern existe :
javascript/\d/.test("abc123"); // true
/\d/.test("abc"); // false
C'est la méthode a utiliser pour la validation. Pas besoin d'extraire quoi que ce soit, juste un oui ou non.
javascriptconst isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
const hasUppercase = /[A-Z]/.test(password);
Je rappelle le piège du flag g (vu dans l'article précédent) : ne réutilisé jamais une regex g avec .test(). Le lastIndex persiste et donne des résultats incoherents.
.match() - Les captures
Méthode de String. Deux comportements différents selon le flag g :
javascript// Sans g : renvoie le premier match avec les groupes de capture
"2026-03-29 et 2026-04-15".match(/(\d{4})-(\d{2})-(\d{2})/);
// ["2026-03-29", "2026", "03", "29", index: 0, groups: undefined]
// Avec g : renvoie tous les matches, MAIS sans les groupes de capture
"2026-03-29 et 2026-04-15".match(/(\d{4})-(\d{2})-(\d{2})/g);
// ["2026-03-29", "2026-04-15"]
C'est un choix de design discutable. Avec g, tu perds les captures. Si tu veux tous les matches ET les captures, il faut .matchAll().
Si aucun match n'est trouve, .match() renvoie null. Pas un tableau vide, null. Pense a vérifier :
javascriptconst matches = text.match(/pattern/g);
const count = matches?.length ?? 0; // Safe
const count2 = text.match(/pattern/g).length; // TypeError si null
.matchAll() - L'itérateur complet
Méthode de String. Renvoie un itérateur avec tous les matches, captures incluses. Necessite le flag g :
javascriptconst text = "dates: 2026-03-29 et 2026-04-15";
const regex = /(?<annee>\d{4})-(?<mois>\d{2})-(?<jour>\d{2})/g;
for (const match of text.matchAll(regex)) {
console.log(match[0]); // "2026-03-29", puis "2026-04-15"
console.log(match.groups.annee); // "2026", puis "2026"
console.log(match.index); // 7, puis 20
}
// Ou convertir en tableau
const allMatches = [...text.matchAll(regex)];
.matchAll() est la méthode a privilegier quand tu veux itérer sur tous les matches avec leurs détails. Elle a ete ajoutee en ES2020 et c'est devenu mon choix par défaut sur paltemps.fr des que j'ai besoin de captures multiples.
Un avantage discret : .matchAll() ne modifie pas lastIndex. Pas de bug d'état.
.replace() et .replaceAll()
Méthodes de String. Remplacent les occurrences matchees :
javascript// replace sans g : remplace la premiere occurrence
"foo bar foo".replace(/foo/, "baz"); // "baz bar foo"
// replace avec g : remplace toutes les occurrences
"foo bar foo".replace(/foo/g, "baz"); // "baz bar baz"
// replaceAll avec regex : necessite le flag g
"foo bar foo".replaceAll(/foo/g, "baz"); // "baz bar baz"
// replaceAll avec string : pas besoin de regex
"foo bar foo".replaceAll("foo", "baz"); // "baz bar baz"
La puissance de .replace() vient de la fonction de remplacement :
javascript// Transformer chaque match avec une fonction
"hello world".replace(/\b\w/g, (char) => char.toUpperCase());
// "Hello World"
// Avec des captures
"2026-03-29".replace(
/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/,
(...args) => {
const { y, m, d } = args.at(-1); // Dernier arg = groups
return `${d}/${m}/${y}`;
}
);
// "29/03/2026"
Les tokens speciaux dans la chaîne de remplacement :
javascript"hello world".replace(/(hello) (world)/, "$2 $1"); // "world hello"
"hello world".replace(/(hello) (world)/, "{{body}}amp; !!"); // "hello world !!"
"hello world".replace(/(hello) (world)/, "
Regex - 10 - Les regex en JavaScript
Toutes les méthodes JavaScript pour utiliser les regex : test, match, matchAll, replace, split, search.
>"); // " >" (avant le match)
"hello world".replace(/(hello) (world)/, "{{body}}#x27; >"); // " >" (apres le match)
.search() - L'index
Méthode de String. Renvoie l'index du premier match, ou -1 :
javascript"hello world".search(/world/); // 6
"hello world".search(/xyz/); // -1
C'est l'équivalent de indexOf() mais avec une regex. Le flag g est ignore.
.split() - Le découpage
Méthode de String. Decoupe une chaîne selon un pattern :
javascript// Split basique
"a,b,,c".split(/,/); // ["a", "b", "", "c"]
// Split avec plusieurs separateurs
"a,b;c|d".split(/[,;|]/); // ["a", "b", "c", "d"]
// Split avec espaces variables
"mot1 mot2\tmot3\n\nmot4".split(/\s+/); // ["mot1", "mot2", "mot3", "mot4"]
// Split avec capture : les separateurs captures sont inclus dans le resultat
"un-deux_trois".split(/([-_])/); // ["un", "-", "deux", "_", "trois"]
Le dernier point est souvent meconnu. Si le separateur a un groupe de capture, le separateur apparaît dans le tableau résultat. Utile quand tu veux tokeniser une chaîne en gardant les delimiteurs.
.exec() - Le contrôle total
Méthode de RegExp. Comme .match() sans flag g : renvoie un match a la fois avec toutes les infos :
javascriptconst regex = /(\d+)/g;
const text = "12 et 34 et 56";
let match;
while ((match = regex.exec(text)) !== null) {
console.log(`Trouve "${match[0]}" a l'index ${match.index}`);
}
// Trouve "12" a l'index 0
// Trouve "34" a l'index 6
// Trouve "56" a l'index 12
Avant .matchAll(), c'etait la seule manière d'itérer sur tous les matches avec captures. Mais .exec() modifie lastIndex, donc les memes pièges qu'avec .test() s'appliquent. Aujourd'hui, préféré .matchAll().
Le bug lastIndex en détail
Pour etre tres clair sur ce piège :
javascriptconst regex = /a/g;
// Chaque appel a exec() ou test() avance lastIndex
regex.exec("aaa"); // match "a" a index 0, lastIndex = 1
regex.exec("aaa"); // match "a" a index 1, lastIndex = 2
regex.exec("aaa"); // match "a" a index 2, lastIndex = 3
regex.exec("aaa"); // null, lastIndex = 0
regex.exec("aaa"); // match "a" a index 0, lastIndex = 1
// Reset manuel
regex.lastIndex = 0; // Repart du debut
Quand le match echoue, lastIndex est remis a 0. Mais si tu changes de chaîne entre deux appels, lastIndex n'est pas remis a zero et la recherche commence au milieu de la nouvelle chaîne.
Résumé
- Prefere le literal
/pattern/ au constructeur sauf pour les patterns dynamiques
.test() pour un booleen, .match() pour le premier match, .matchAll() pour tout
.match() avec g perd les captures, utilise .matchAll() a la place
.replace() accepte une fonction pour des remplacements complexes
.split() avec capture inclut les separateurs dans le résultat
- Le flag
g + lastIndex est la source de bug la plus frequente avec les regex en JS
Article précédent : 09 - Les flags
Article suivant : 11 - Patterns courants
Sources