Guides1 chasse jouable incluse

Les classes de caractères en regex : \d, \w, \s, [a-z] et leurs pièges

Les classes de caractères sont la partie la plus utilisée des regex, et celle où l'on se trompe le plus facilement sans s'en rendre compte. Ce que [abc], [a-z], [^…], \d, \w et \s trouvent vraiment, et les pièges qui se cachent derrière : [A-z], le tiret égaré, le point entre crochets et les chiffres qui ne sont pas de 0 à 9.

Logo de Regex Hunter

· 8 min de lecture

/^[A-Z][a-z]+$/

à attraper

  • Paris
  • Lima
  • Oslo
  • Rome

à épargner

  • paris
  • PARIS
  • New York
  • R2D2

Une classe de caractères correspond à un caractère d'un ensemble. [aeiou] correspond à une voyelle. [0-9] correspond à un chiffre. \s correspond à un espace, une tabulation ou un saut de ligne.

On les retrouve dans presque tous les motifs, et la plupart de leurs pièges sont silencieux : le motif marche sur les entrées que vous avez testées, puis laisse passer quelque chose de bizarre plus tard. Cet article explique ce que chaque classe trouve vraiment, puis passe aux pièges. Chaque exemple est interactif : modifiez les motifs et regardez les lignes changer.

01Un ensemble entre crochets

Les crochets listent les caractères autorisés à une position :

Correspondances4/4 comme prévu
/gr[ae]y/

Doit correspondre2/2

  • grey
  • gray

Ne doit pas2/2

  • groy
  • greay
Essayez-le dans le bac à sable
Un caractère de l'ensemble, a ou e, entre gr et y.

greay échoue parce que la classe occupe exactement une case. Pour autoriser plus d'un caractère, ajoutez un quantificateur après : [ae]+.

02Les plages

Un tiret entre deux caractères signifie « tout ce qui se trouve entre les deux », selon le code des caractères :

Correspondances5/5 comme prévu
/^[A-Z][a-z]+$/

Doit correspondre2/2

  • Paris
  • Lima

Ne doit pas3/3

  • paris
  • PARIS
  • New York
Essayez-le dans le bac à sable
Une majuscule, puis une ou plusieurs minuscules, et rien d'autre.

Vous pouvez mettre plusieurs plages et caractères isolés dans une même classe : [A-Za-z0-9_] regroupe lettres, chiffres et tiret bas.

03Les classes négatives

Un ^ juste après le crochet ouvrant inverse l'ensemble : « n'importe quel caractère sauf ceux-ci ».

Correspondances5/5 comme prévu
/^[^aeiou]+$/

Doit correspondre3/3

  • rhythm
  • myths
  • 2024

Ne doit pas2/2

  • cat
  • queue
Essayez-le dans le bac à sable
Uniquement des caractères qui ne sont pas des voyelles minuscules, du début à la fin.

Attention : « n'importe quel caractère sauf » veut vraiment dire n'importe lequel : espaces, chiffres, ponctuation et sauts de ligne comptent tous. 2024 correspond, car les chiffres ne sont pas des voyelles.

En dehors des crochets, ^ est une ancre. À l'intérieur, tout au début, c'est une négation. Partout ailleurs à l'intérieur, c'est juste un accent circonflexe.

04Les raccourcis

Certaines classes sont si courantes qu'elles ont un nom court :

Raccourci Signification (en JavaScript) Contraire
\d un chiffre, [0-9] \D
\w un caractère de mot, [A-Za-z0-9_] \W
\s un espacement : espace, tabulation, saut de ligne et compagnie \S
. n'importe quel caractère sauf un saut de ligne

Deux d'entre eux surprennent. \w inclut les chiffres et le tiret bas, ce n'est donc pas « une lettre » :

Correspondances5/5 comme prévu
/^\w+$/

Doit correspondre3/3

  • hello
  • snake_case
  • R2D2

Ne doit pas2/2

  • kebab-case
  • two words
Essayez-le dans le bac à sable
Les tirets bas et les chiffres sont aussi des caractères de mot. Les tirets et les espaces, non.

Et \s ne se limite pas à l'espace : il correspond aussi aux tabulations et aux sauts de ligne. Si vous voulez exactement un espace, écrivez un espace.

05Piège 1 : [A-z] ne veut pas dire « toutes les lettres »

Les plages suivent les codes des caractères. Entre Z (90) et a (97) se trouvent six autres caractères : [ \ ] ^ _ et l'accent grave. Donc [A-z] les laisse passer :

Correspondances4/4 comme prévu
/^[A-z]+$/

Doit correspondre3/3

  • Hello
  • snake_case
  • up^down

Ne doit pas1/1

  • 2024
Essayez-le dans le bac à sable
Les deux dernières lignes correspondent aussi. Le tiret bas et l'accent circonflexe se trouvent entre Z et a dans la table des caractères.

Écrivez les deux plages séparément : [A-Za-z].

06Piège 2 : le tiret au milieu

Un tiret entre deux caractères crée une plage, même quand vous vouliez un tiret littéral :

Correspondances3/3 comme prévu
/^[\w+-.]+$/
  • a+b
  • a.b
  • a,b
Essayez-le dans le bac à sable
Le +-. du milieu est lu comme une plage allant de + à ., qui se trouve inclure la virgule.

Cette virgule, c'est le bug : + a le code 43, . le 46, et la virgule (44) se trouve entre les deux. Placez le tiret en premier ou en dernier dans la classe, ou échappez-le, et ce redevient un simple tiret :

Correspondances4/4 comme prévu
/^[\w+.-]+$/

Doit correspondre3/3

  • a+b
  • a.b
  • a-b

Ne doit pas1/1

  • a,b
Essayez-le dans le bac à sable
Tiret en dernier : il signifie maintenant un tiret, et la virgule est exclue.

07Piège 3 : le point et les autres caractères spéciaux

La plupart des caractères spéciaux perdent leurs pouvoirs entre crochets. [.] est un point littéral, [*+?] est l'un de ces trois symboles, et [$] est un signe dollar. [.] est donc une autre façon d'écrire \. :

Correspondances4/4 comme prévu
/^\d+[.]\d+$/

Doit correspondre2/2

  • 3.14
  • 10.5

Ne doit pas2/2

  • 3x14
  • 314
Essayez-le dans le bac à sable
Entre crochets, le point n'est qu'un point.

Seuls quatre caractères restent spéciaux dans une classe : ], \, ^ au début, et - entre deux caractères.

08Piège 4 : des chiffres qui ne sont pas de 0 à 9

En JavaScript, \d vaut exactement [0-9]. En Python 3, sur un motif str normal, \d correspond à n'importe quel chiffre Unicode : les chiffres indo-arabes comme ٣, devanagari comme ३ ou pleine chasse comme 3. Il en va de même pour \w, qui accepte les lettres de n'importe quelle écriture.

import re

re.fullmatch(r"\d+", "٣٤٥")           # matches in Python
re.fullmatch(r"\d+", "٣٤٥", re.ASCII)  # None

Si un nombre est sur le point de passer dans int() ou dans une colonne de base de données, ça compte. Utilisez [0-9], ou le marqueur re.ASCII, quand vous voulez des chiffres ASCII.

09À vous de jouer

Saurez-vous attraper les lignes composées uniquement de chiffres hexadécimaux ?

Chasse jouablepar 13

Attrapez les chaînes composées uniquement de chiffres hexadécimaux, en majuscules ou en minuscules.

Cibles · 0/6 attrapées

  • ffcible
  • 00cible
  • 1a2Bcible
  • DEADbeefcible
  • c0ffeecible
  • 7cible

Innocents · erreurs : 0

  • fginnocent
  • 0x1finnocent
  • 12 34innocent
  • beef!innocent
  • gginnocent
  • zinnocent

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

10Récapitulatif

  • [abc] correspond à un caractère de l'ensemble. Ajoutez un quantificateur pour en avoir plus.
  • [^abc] correspond à tout caractère absent de l'ensemble, espaces et sauts de ligne compris.
  • Écrivez [A-Za-z], jamais [A-z].
  • Placez un tiret littéral en premier ou en dernier : [\w.-].
  • Entre crochets, . * + ? $ sont littéraux.
  • \w inclut les chiffres et _. \s inclut les tabulations et les sauts de ligne.
  • En Python, \d et \w gèrent l'Unicode. Utilisez [0-9] ou re.ASCII pour vous limiter à l'ASCII.

11Continuez à vous entraîner