Guides1 chasse jouable incluse

Les marqueurs de regex expliqués : i, g, m, s, u, y et d

Ce que change chaque marqueur (flag) de regex en JavaScript, avec des exemples interactifs : i pour ignorer la casse, g global (et le piège de lastIndex), m multiligne, s dotAll, u unicode, y sticky et d indices, plus la façon dont Python exprime les mêmes idées.

Logo de Regex Hunter

· 5 min de lecture

/^colou?r$/i

à attraper

  • color
  • Colour
  • COLOR
  • colour

à épargner

  • colr
  • colours
  • discolor
  • kolor

Un marqueur (flag) change le comportement du motif tout entier. En JavaScript, les marqueurs se placent après la barre oblique fermante : /cat/gi. En Python, ce sont des arguments, comme re.IGNORECASE, ou des marqueurs en ligne au début du motif, comme (?i).

JavaScript en compte sept. Vous en utiliserez deux en permanence, quelques-uns de temps en temps, et l'un d'eux cache un piège dans lequel presque tout le monde est tombé. Chaque exemple est interactif : modifiez les motifs et regardez les lignes changer.

01i : ignorer la casse

Les lettres correspondent en majuscules comme en minuscules :

Correspondances5/5 comme prévu
/^colou?r$/i

Doit correspondre3/3

  • color
  • Colour
  • COLOR

Ne doit pas2/2

  • colours
  • discolor
Essayez-le dans le bac à sable
Avec i, le motif accepte n'importe quel mélange de majuscules et de minuscules.

Cela vous évite d'écrire [Cc][Oo][Ll]…, et cela vaut aussi dans les classes : avec i, [a-z] accepte également les majuscules.

Python : re.IGNORECASE, re.I ou (?i).

02g : global

Sans g, une regex trouve la première correspondance et s'arrête. Avec g, des méthodes comme match, matchAll et replace agissent sur toutes les correspondances :

"a1b22c333".match(/\d+/);    // ["1"], plus index and input
"a1b22c333".match(/\d+/g);   // ["1", "22", "333"]
"a-b-c".replace(/-/, "+");   // "a+b-c"
"a-b-c".replace(/-/g, "+");  // "a+b+c"

Python n'a pas de g. À la place, vous choisissez la fonction : re.search trouve une correspondance, re.findall et re.finditer les trouvent toutes, et re.sub remplace tout par défaut.

Le piège de lastIndex

Une regex avec g (ou y) mémorise où sa dernière correspondance s'est terminée, dans lastIndex, et le test() suivant repart de là. Réutilisez une telle regex sur plusieurs chaînes et les résultats se mettent à alterner :

const hasDigit = /\d/g;

hasDigit.test("a1");  // true, lastIndex is now 2
hasDigit.test("b2");  // false: the search starts at index 2, past the "2"
hasDigit.test("b2");  // true again, lastIndex had reset to 0

La solution est simple : ne mettez pas g sur une regex que vous n'utilisez qu'avec test(). Vous n'en avez pas besoin pour vérifier si quelque chose correspond.

03m : multiligne

^ et $ correspondent au début et à la fin de chaque ligne au lieu du texte entier. L'article sur les ancres et le mode multiligne traite le sujet en détail.

"one\ntwo".match(/^\w+$/gm);  // ["one", "two"]

Python : re.MULTILINE, re.M ou (?m).

04s : dotAll

Normalement, . correspond à n'importe quel caractère sauf un saut de ligne. Avec s, il accepte aussi les sauts de ligne :

/start.*end/.test("start\nend");   // false
/start.*end/s.test("start\nend");  // true

Avant l'arrivée de s, on écrivait [\s\S] pour dire « absolument n'importe quel caractère », et on le croise encore dans du code ancien.

Python : re.DOTALL, re.S ou (?s).

05u : unicode

u fait travailler le motif sur des caractères Unicode entiers plutôt que sur des morceaux UTF-16, et active les échappements de propriété comme \p{L} (n'importe quelle lettre, dans n'importe quelle écriture) :

Correspondances6/6 comme prévu
/^\p{L}+$/u

Doit correspondre4/4

  • hello
  • café
  • Zürich
  • Москва

Ne doit pas2/2

  • R2D2
  • two words
Essayez-le dans le bac à sable
\p{L} est une lettre de n'importe quel alphabet, accents compris. [a-z] rejetterait toutes les lignes sauf la première.

Il fait aussi correspondre . à un emoji entier plutôt qu'à une moitié d'emoji, et il rend l'analyseur strict : un échappement inutile comme \- hors d'une classe devient une erreur de syntaxe au lieu d'être ignoré en silence. Le marqueur v, plus récent en JavaScript, est un sur-ensemble plus strict de u qui permet des opérations d'ensembles dans les classes.

Le module re de Python gère l'Unicode par défaut mais n'a pas de \p{…}. Le module tiers regex l'ajoute.

06y : sticky

Avec y, une correspondance doit commencer exactement à lastIndex, pas n'importe où après. Il sert surtout aux analyseurs lexicaux (tokenizers) qui parcourent une chaîne morceau par morceau :

const word = /\w+/y;

word.lastIndex = 0;
word.exec("hi there");  // ["hi"], lastIndex is now 2
word.exec("hi there");  // null: index 2 is a space, and y won't skip ahead

07d : indices

d ajoute à chaque correspondance un tableau indices avec le début et la fin de la correspondance et de chaque groupe :

const m = /(\d+)-(\d+)/d.exec("pages 12-30");

m.indices[0];  // [6, 11], the whole match
m.indices[1];  // [6, 8], the first group, "12"

Pratique pour surligner les correspondances dans un éditeur. Python le propose d'origine : m.span(1).

08À vous de jouer

Utilisez le marqueur i pour que votre solution reste courte :

Chasse jouablepar 5

Attrapez yes quelle que soit la casse, et rien d'autre.

Cibles · 0/5 attrapées

  • yescible
  • Yescible
  • YEScible
  • yEscible
  • yeScible

Innocents · erreurs : 0

  • yesterdayinnocent
  • eyesinnocent
  • noinnocent
  • yeinnocent
  • y e sinnocent

Tapez une regex — le plateau se met à jour en direct.

Essayez-le dans le bac à sable
Ça vous plaît ? Une nouvelle chasse chaque jour.Jouer la chasse du jour

09Récapitulatif

  • i ignore la casse. m applique ^ et $ à chaque ligne. s permet à . d'accepter les sauts de ligne.
  • g trouve toutes les correspondances, mais ne l'utilisez pas avec test() sur une regex réutilisée.
  • u gère tout l'Unicode et active \p{L}.
  • y ne trouve une correspondance qu'à lastIndex. d ajoute les positions des correspondances.
  • Python : re.I, re.M, re.S, ou en ligne (?i), (?m), (?s). Pas de g : utilisez findall ou sub.

10Continuez à vous entraîner