Regex - 09 - Les flags

Tous les flags regex en JavaScript : g, i, m, s, u, v, d et leurs pièges.

09 - Les flags

Ce que tu vas apprendre

  • Les 7 flags disponibles en JavaScript : g, i, m, s, u, v, d
  • Le piège du flag g avec lastIndex
  • Le flag u et le support Unicode
  • Le flag v (unicodeSets) et les opérations sur les ensembles
  • Combiner les flags efficacement

Prerequisites

08 - Lookahead et lookbehind


Les flags modifient le comportement global d'une regex. Tu les mets apres le dernier slash : /pattern/flags. La plupart des développeurs connaissent g et i, mais les autres flags sont tout aussi utiles. Et le flag g cache un piège vicieux que la majorite des gens decouvrent par un bug en production.

g - Global

Sans g, la regex s'arrêté au premier match. Avec g, elle trouve tous les matches :

javascript"aaa bbb aaa".match(/aaa/);   // ["aaa"] (premier seulement)
"aaa bbb aaa".match(/aaa/g);  // ["aaa", "aaa"] (tous)

Simple en apparence. Mais g change le comportement de .test() et .exec() de manière inattendue :

javascriptconst regex = /abc/g;

regex.test("abc xyz abc"); // true  (lastIndex = 3)
regex.test("abc xyz abc"); // true  (lastIndex = 11)
regex.test("abc xyz abc"); // false (lastIndex = 0)
regex.test("abc xyz abc"); // true  (lastIndex = 3)

Chaque appel a .test() reprend là où le précédent s'est arrêté. La regex garde un état interne via la propriété lastIndex. Ca signifie que si tu utilises la meme regex g dans une boucle de validation, tu auras des résultats alternant entre true et false.

javascript// BUG classique
const emailRegex = /\w+@\w+\.\w+/g;

function isValid(email) {
  return emailRegex.test(email); // lastIndex persiste entre les appels !
}

isValid("user@test.com"); // true
isValid("user@test.com"); // false (!!)
isValid("user@test.com"); // true

La regle : n'utilise jamais g avec .test() si tu reutilises la meme instance de regex. Soit tu créés une nouvelle regex a chaque appel, soit tu retires le flag g.

i - Case Insensitive

Ignore la casse :

javascript/hello/i.test("Hello");  // true
/hello/i.test("HELLO");  // true
/hello/i.test("hElLo");  // true

Rien de surprenant. Mais attention avec les caractères Unicode : le flag i seul ne gere pas les equivalences de casse Unicode. Pour ca, il faut combiner avec u.

javascript/\u00e9/i.test("\u00c9");    // true (e avec accent)
/cafe/i.test("CAFE");         // true

m - Multiline

Change le comportement de ^ et $. Sans m, ils matchent le début et la fin de la chaîne entière. Avec m, ils matchent le début et la fin de chaque ligne :

javascriptconst texte = "premiere ligne\ndeuxieme ligne\ntroisieme ligne";

texte.match(/^\w+/g);   // ["premiere"] (debut de chaine)
texte.match(/^\w+/gm);  // ["premiere", "deuxieme", "troisieme"] (debut de chaque ligne)

texte.match(/\w+$/g);   // ["ligne"] (fin de chaine)
texte.match(/\w+$/gm);  // ["ligne", "ligne", "ligne"] (fin de chaque ligne)

Le flag m est indispensable quand tu traites du texte multiligne. Sans lui, tu rates tout ce qui n'est pas sur la première ou dernière ligne.

s - DotAll

Par défaut, le point . matche tout sauf les retours a la ligne (\n). Le flag s change ca :

javascriptconst html = "<div>\n  contenu\n</div>";

/<div>.*<\/div>/.test(html);   // false (le . ne passe pas le \n)
/<div>.*<\/div>/s.test(html);  // true (le . matche tout, y compris \n)

Avant ES2018, on utilisait [\s\S] comme remplacement du "vrai point" :

javascript/<div>[\s\S]*<\/div>/.test(html);  // true (le hack pre-ES2018)

Le flag s est plus propre. Utilise-le quand tu travailles avec du texte multiligne et que tu veux que . matche vraiment tout.

u - Unicode

Le flag u active le support Unicode complet. Sans lui, JavaScript traite les chaînes comme des sequences de code units UTF-16, ce qui casse avec les caractères hors du Basic Multilingual Plane :

javascript// Sans u : un emoji est vu comme 2 caracteres
/^.$/.test("a]");   // false (2 code units)

// Avec u : un emoji est vu comme 1 caractere
/^.$/u.test("a]");  // Depends on the emoji

// Plus concretement
"😀".length;        // 2 (JS voit 2 code units)
/^.$/u.test("😀");  // true (u voit 1 code point)
/^.$/.test("😀");   // false

Le flag u debloque aussi les propriétés Unicode \p{...} :

javascript// Matcher toutes les lettres Unicode (pas juste ASCII)
/\p{Letter}/u.test("e");   // true
/\p{Letter}/u.test("e");   // true (accent)
/\p{Letter}/u.test("7");   // false

// Matcher les emojis
/\p{Emoji}/u.test("😀");   // true

// Matcher les lettres grecques
/\p{Script=Greek}/u.test("α");  // true

Sur paltemps.fr, le flag u est systématique dans mes regex. On vit dans un monde Unicode, et ignorer ca c'est s'exposer a des bugs subtils avec les accents, les emojis et les alphabets non-latins.

v - UnicodeSets (ES2024)

Le flag v est l'évolution du flag u. Il apporte les opérations sur les ensembles dans les classes de caractères :

javascript// Soustraction : lettres sauf les voyelles
/[\p{Letter}--[aeiouAEIOU]]/v.test("b"); // true
/[\p{Letter}--[aeiouAEIOU]]/v.test("a"); // false

// Intersection : caracteres qui sont a la fois lettre et ASCII
/[\p{Letter}&&\p{ASCII}]/v.test("a");    // true
/[\p{Letter}&&\p{ASCII}]/v.test("e");    // false (accent, pas ASCII)

// Union imbriquee
/[[\p{Script=Greek}][\p{Script=Latin}]]/v.test("α"); // true
/[[\p{Script=Greek}][\p{Script=Latin}]]/v.test("a"); // true

Le flag v est incompatible avec u. Tu utilises l'un ou l'autre, jamais les deux.

d - HasIndices

Le flag d ajoute les positions de début et fin de chaque groupe capture :

javascriptconst regex = /(?<annee>\d{4})-(?<mois>\d{2})/d;
const match = "date: 2026-03".match(regex);

console.log(match.indices[0]);          // [6, 13] (match complet)
console.log(match.indices[1]);          // [6, 10] (groupe 1: annee)
console.log(match.indices.groups.annee); // [6, 10]
console.log(match.indices.groups.mois);  // [11, 13]

Utile pour du syntax highlighting ou quand tu dois savoir exactement ou chaque capture se situe dans la chaîne originale.

Combiner les flags

Les flags se cumulent :

javascript// Recherche globale, insensible a la casse, multiligne, Unicode
const regex = /^bonjour/gimu;

// DotAll + global pour parser du HTML multiligne
const htmlRegex = /<div class="content">.*?<\/div>/gs;

Les combinaisons les plus courantes :

  • gi : trouver tous les matches sans tenir compte de la casse
  • gm : trouver des patterns au début/fin de chaque ligne
  • gs : matcher à travers les retours a la ligne
  • gu : recherche globale avec support Unicode

Verifier les flags d'une regex

javascriptconst regex = /test/giu;

console.log(regex.flags);      // "giu"
console.log(regex.global);     // true
console.log(regex.ignoreCase); // true
console.log(regex.unicode);    // true
console.log(regex.multiline);  // false

Résumé

  • g : tous les matches, mais attention au piège de lastIndex avec .test()
  • i : insensible a la casse
  • m : ^ et $ matchent par ligne au lieu de la chaîne entière
  • s : le point . matche aussi \n
  • u : support Unicode complet et propriétés \p{}
  • v : opérations sur les ensembles dans les classes de caractères (ES2024)
  • d : indices de position de chaque capture
  • Ne jamais réutiliser une regex g avec .test() sans reset du lastIndex

Article précédent : 08 - Lookahead et lookbehind Article suivant : 10 - Regex en JavaScript

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.