• Facile

Ce cours est visible gratuitement en ligne.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mis à jour le 14/08/2017

L'objet "RegExp"

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Nous allons maintenant aborder un objet qui nous offre plus de contrôles sur les chaînes de caractères.
On le surnomme regex ; son nom est RegExp, pour Regular Expression, ce qui se traduit par "expression rationnelle" (une autre traduction, moins parlante, est "expression régulière").

Note : dans ce chapitre, les regex seront écrites de cette façon.

Sommaire

Créer une regex

Tout ce qu'il faut savoir pour créer une regex.
Il faut bien une sous-partie pour ça ;) .

Quelques exemples

On va créer des regex pour vérifier :

  • une adresse e-mail

  • un numéro de téléphone français.

Utiliser une regex

Ici, reg désigne une regex et str une chaîne de caractères.

  • reg.test(str) : renvoie true si str vérifie la regex, false sinon.

  • reg.exec(str) : applique la regex à la chaîne, renvoie le résultat.

  • str.match(reg) : applique la regex à la chaîne, renvoie le(s) résultat(s).

  • str.replace(reg, str2) : remplace le(s) sous-chaîne(s) vérifiant la regex par str2 et renvoie le résultat.

  • str.search(reg) : renvoie la position de la première sous-chaîne vérifiant la regex.

  • str.split(reg) : pour "découper" une chaîne.

Créer une regex

Créer une regex

Avant de se lancer...

Pour tester une regex, nous allons utiliser la méthode nommée test de cet objet, qui s'utilise ainsi :

var verifie = maRegex.test(str);

Si la chaîne de caractères str vérifie la regex maRegex, alors verifie vaut true, sinon il vaut false.

Une regex... pourquoi ?!

C'est bien beau, mais comment ça fonctionne ? o_O
Ça veut dire quoi "vérifier une regex" ?

Si on devait formuler une phrase pour décrire les regex, ce serait celle-ci :

Citation : les regex

L'utilisation des regex consiste à chercher un motif dans la chaîne de caractères.

Avec test, on récupère simplement true si le motif est trouvé dans la chaîne de caractères, false sinon.
Mais on peut également récupérer les morceaux de chaînes qui satisfont le motif, ou encore les remplacer par autre chose.

Première regex

Il est maintenant temps de créer une première regex...
Sachez qu'il y a pour cela deux façons, qui reviennent au même.

La première, grâce à laquelle on voit bien que RegExp est une classe d'objet :

var maRegex = new RegExp("motif", "flags");

La seconde, dont la syntaxe est moins lourde :

var maRegex = /motif/flags;
On essaie !

Essayons donc sans plus tarder :

var reg = new RegExp("toto");
var resultat = reg.test("toto");
alert(resultat);

Ce qui affiche true, normal ^^ .

Deuxième essai, avec la même regex :

var reg = /toto/;
var resultat = reg.test("Bonjour toto !");
alert(resultat);

Ce qui affiche également true, car la chaîne de caractères qui forme le motif (c'est "toto") a été trouvée dans notre phrase (qui est "Bonjour toto !").

Une regex un peu plus évoluée

Les flags

Comme nous l'avons dit, une regex est constitué de deux choses :

  • un motif, qui sera recherché dans les chaînes de caractères auxquelles on appliquera notre regex,

  • des flags, qui sont des options supplémentaires.

Revenons sur ces derniers, qui ne devraient pas vous poser de difficultés.
Ils sont au nombre de trois :

  • i, pour rechercher le motif sans tenir compte de la casse (des majuscules / minuscules),

  • g, signifiant "global", dont on précisera l'utilisation en temps voulu (quand on parlera des fonctions utilisant les regex),

  • gi = g + i :D (pour combiner les deux options).

Des symboles bizarres

Maintenant que vous savez tout des flags, concentrons-nous sur les motifs, car c'est une autre paire de manches :-° .

Des symboles particuliers vont nous aider à rendre nos motifs beaucoup plus évolués. Vous verrez, avec tous ces symboles, un motif complet ressemble à du martien. :D

Le premier symbole est | (la barre verticale) et signifie OU.
Par exemple, pour vérifier si la chaîne contient sdz ou SdZ (avec ces majuscules) : /sdz|SdZ/
Cette regex vérifie "Vive le SdZ !" et "Je suis sur le sdz", mais pas "Le SDZ ?".
On peut utiliser des parenthèses pour délimiter : /(st|h|p)op/ est vérifié par "stop !", "Le shopping", "pop-up", mais pas par "flop".

Le symbole suivant est . (le point), qui signifie "n'importe quel caractère".
Ainsi, /o.o/i (notez le flag i pour ignorer la casse) sera satisfaite par : "o,O", "Toto" et "automobile".

Début et fin de chaîne

Deux symboles nous permettent de délimiter le début et la fin de la chaîne de caractères : ce sont respectivement ^ et $.

Par exemple, /^Bonjour/ sera satisfaite uniquement avec une phrase commençant par "Bonjour", comme "Bonjour monsieur", mais pas par "Hey ! Bonjour toi !".
Autre exemple, /!$/ va vérifier si une phrase se termine par un point d'exclamation, comme "Hey ! Bonjour toi !", mais pas comme "Toto ?!?"

Encore plus de symboles

Les classes

Il est également possible de définir, au lieu d'un seul caractère, une liste de caractères (appelée classe de caractères), en les indiquant entre crochets [].

Avec /t[iaot]c/, on peut ainsi filtrer "Et toc !", "Tic, tac...", "25? ttc", mais pas "tuc".

À l'intérieur d'une classe, il est possible d'utiliser le tiret pour définir une plage de valeur : [i-n] équivaut à [ijklmn], et [0-9A-F] à [0123456789ABCDEF].
On peut ainsi chercher si une phrase se termine par une lettre ou un chiffre avec /[a-zA-Z0-9]$/, vérifiée par "Bonjour", "BOB" et "Agent 007", mais pas par "Non." ni "(-_-)".

Inversement, on peut définir une classe en indiquant les caractères qui ne doivent pas y figurer, grâce à ^ placé au début de cette classe.
Exemple : pour détecter les phrases qui ne se terminent pas par une lettre, on peut utiliser /[^a-zA-Z]$/, que vérifie "Agent 007" mais pas "Toto".

Classes existantes

Certaines classes très utilisées sont déjà définies : en voici les principales.

Nom

Équivalent

Description

\d

[0-9]

Un chiffre

\D

[^0-9]

Caractère qui n'est pas un chiffre

\w

[a-zA-Z0-9_]

Caractère alpha-numérique, ou underscore

\W

[^a-zA-Z0-9_]

Caractère non alpha-numérique (autre que underscore)

\s

Caractère "blanc" (espace, saut de ligne, tabulation, etc.)

\S

Caractère "non-blanc"

\b

Début / fin de mot (début de chaîne, espace, etc.)

\B

Ni début ni fin de mot

Les quantificateurs

Il est possible de préciser le nombre de fois que doit se répéter un "bout de motif".

Quantifier "manuellement"

On peut préciser, entre accolades {}, le nombre de fois qu'un caractère / groupe de caractères doit se répéter.
Dans cet exemple, on veut filtrer "foot" avec deux "o" : /fo{2}t/

Il est possible d'indiquer une plage de valeur : on demande au groupe de caractères de se répéter au minimum i fois, et au maximum j fois, avec {i,j}.
Par exemple, /bo{2,5}m/ cherchera "boom" avec 2, 3, 4 ou 5 "o".

Notez que la valeur supérieure est facultative.
Ainsi, /bo{2,}m/ sera validé par "boom" et par "boooooom" : avec 2 "o" ou plus.

D'autres symboles pour quantifier

Il existe les symboles ?* et + en guise de "raccourcis".

Nom

Équivalent

En français

?

{0,1}

0 ou 1 fois

*

{0,}

N'importe quel nombre de fois

+

{1,}

Au moins une fois

Symbole utilisé = symbole à échapper !

Et si on veut utiliser le point dans nos regex, comment faire ?
Si on l'écrit comme ça, il veut dire "n'importe quelle caractère" !

Pour utiliser en dehors d'une classe l'un des symboles, mais en tant que caractère, il faut l'échapper en le faisant précéder d'un antislash.
Exemple : pour savoir si une chaîne se termine par ".com", on utilisera /\.com/

Voici une liste de symboles à échapper : | . ^ $ ( ) [ ] - { } ? * + \ /

À l'intérieur d'une classe, inutile d'échapper les caractères autres que ^ [ ] - \.

Parenthèses : avec ou sans capture ?

Ce qu'on n'a pas encore dit...

Il est également possible de savoir quelles sous-chaînes satisfont le motif, et on va même pouvoir utiliser les regex pour en extraire certains morceaux.
Ainsi, dans une phrase telle que "les horaires sont 16h45, 17h, 17h20 et 17h40", il est possible d'extraire toutes les heures à l'aide d'une simple regex.

Puissant ! :soleil:

Les parenthèses capturantes

Pour extraire certains morceaux d'une chaîne de caractères, il faut les délimiter dans notre motif. Pour ce faire, on utilise les parenthèses, qui sont dites capturantes.

Un exemple : on veut extraire l'âge du visiteur, qui se trouve dans une chaîne du type "J'ai 99 ans".
Construisons notre motif lentement... on va d'abord se baser sur "j'ai" et "ans", sans tenir compte de la casse : /j\'ai - ans/i
Ces mots sont séparés de l'âge par un blanc (éventuellement, l'utilisateur peut écrire "99ans" sans espace) : /j\'ai\s - \s?ans/i
Maintenant, on ajoute les chiffres (1, 2 ou 3 chiffres), en les capturant grâce aux parenthèses : /j\'ai\s(\d{1,3})\s?ans/i

On a donc notre regex /j\'ai\s(\d{1,3})\s?ans/i o_O
Elle va nous permettre d'extraire l'âge (dans notre exemple, 99).
Pour l'instant, on ne sait pas comment récupérer le contenu ; en fait, ça va dépendre de la fonction utilisée, on en reparlera donc quand on présentera les fonctions.

Et si on veut des parenthèses qui ne capturent pas ?

Cependant, on peut avoir besoin de parenthèses, mais sans pour autant vouloir en capturer le contenu (par exemple, avec le symbole | vu plus haut).

Il est possible de les rendre non-capturantes, en les faisant commencer par ?:.
Reprenons un exemple vu plus haut, en rendant les parenthèses non capturantes : /(?:st|h|p)op/

Les assertions

Terminons la théorie par un point un peu plus délicat. :-°
Supposons que nous voulions rechercher "bon", mais uniquement dans le mot "bonjour"...

On pourrait utiliser des parenthèses capturantes, de cette manière : /(bon)jour/.
Ainsi, "Bien le bonjour, mon bon monsieur" vérifiera ce motif.
On récupère donc deux choses : le "bonjour", qui satisfait le motif, et le "bon", capturé par les parenthèses.

Mais il est possible d'utiliser ce qu'on appelle une assertion : le symbole (?= (à placer entre parenthèses) à la fin du motif, signifie "si le motif est suivi de".
Dans l'exemple précédent, ceci nous donne /bon(?=jour)/. Comprenez-le ainsi : "bon, s'il est suivi de jour".
Ainsi, dans la phrase "Bien le bonjour, mon bon monsieur", seul le "bon", s'il est suivi de "jour", est sélectionné. :)

Il existe de même le symbole ?!, en fin de motif lui aussi, signifiant "si le motif n'est pas suivi de".
Ainsi, /bon(?!jour)/ (comprenez : "bon, s'il n'est pas suivi de jour") appliqué à la même phrase nous donnera ce résultat : "Bien le bonjour, mon bon monsieur".

Quelques exemples

Quand est-ce qu'on utilise des expressions régulières ?
Parce que c'est bien joli de rechercher "toto" dans une phrase, mais en pratique...

En JavaScript, il est courant d'avoir à vérifier des formulaires avant de les valider. Et pour cela, les regex constituent un outil excellent, car elles permettent de contrôler très précisément toutes les informations données par le visiteur.

Revenons à nos moutons : nous voulions créer des regex pour vérifier si le pseudonyme donné par le visiteur n'est pas trop long, si l'âge qu'il a saisi est valide, s'il n'a pas donné une adresse e-mail qui n'en est pas une, si son numéro de téléphone est vraisemblable, etc.

Le pseudonyme

Tout d'abord, on demande un pseudonyme à l'utilisateur.
Seulement voilà : pour éviter les trucs complètement tordus qui risquent de nous embêter par la suite, on va demander à ce qu'il comporte entre 3 et 16 lettres, avec éventuellement des chiffres et des tirets (hauts et bas).

Voici donc une regex, toute simple, pour vérifier ceci :
/^[a-zA-Z0-9_-]{3,16}$/

Libre à vous d'adapter à vos besoins, ceci n'est qu'un exemple...

L'âge

Pour vérifier l'âge, deux solutions s'offrent à nous...

La première consiste à convertir la valeur en nombre (entier), pour la comparer à un âge minimum et à un âge maximum.
Prenons par exemple 5 et 100 ans comme âges limites, et créons une fonction qui renvoie true si l'âge passé en paramètre est valide :

function ageValide(valeur)
{
     var age = parseInt(valeur);   // on convertit la valeur en nombre entier
     var estValide = !isNaN(age) && (age >= 5) && (age <= 100);
     return estValide;
}

La seconde solution : en utilisant une regex !
On veut que l'âge soit composé d'un ou deux chiffres (on pourrait en prendre 3, ça ne change pas grand-chose au final).
Pour rappel, la classe [0-9] peut s'écrire \d.
Ce qui nous donne :
/^\d{1,2}$/

Le numéro de téléphone

Passons maintenant au numéro de téléphone, dans le cas où c'est un numéro français (le principe reste bien sûr le même pour tous les pays).

Pour rappel, un numéro français est constitué de 5 groupes de 2 chiffres.
Le premier chiffre est toujours un 0 ; le second chiffre peut être soit 1, 2, 3, 4, 5 (selon la région), soit 6 (pour les portables), soit 8 (numéros spéciaux).
Pour séparer les groupes de chiffres, on va considérer que l'utilisateur utilisera soit un espace, soit un tiret, soit un point (soit il ne les sépare pas).

Au passage, nous allons choisir de capturer chacun des groupes de chiffres (ce qui permettra, si besoin est, de ne retenir que les chiffres, sans les séparateurs).

Décomposons donc notre regex...

  • /[ _.-]?/ pour un séparateur (je vous rappelle que le ? est équivalent à {0,1}, car le séparateur est facultatif).

  • /[ _.-]?(\d{2})/ : on ajoute deux chiffres après le séparateur, et on les capture grâce aux parenthèses.

  • /(?:[ _.-]?(\d{2})){4}/ : on répète 4 fois ce groupe "séparateur + 2 chiffre". Pour le délimiter, on utilise des parenthèses non capturantes.
    Pour l'instant, on capture donc les numéros tels que "-12-34-56-78".

  • /(0[1-68])(?:[ _.-]?(\d{2})){4}/ : on ajoute (et on capture avec les parenthèses) le premier groupe de 2 chiffres, dont le premier est forcément un 0, et le second est 1, 2, 3, 4, 5, 6 ou 8.

  • /^(0[1-68])(?:[ _.-]?(\d{2})){4}$/ : on ancre la regex : le numéro commence au début de la chaîne et se termine à la fin.

Ce qui nous donne la magnifique regex suivante, prête à l'emploi :

var regexTel = /^(0[1-68])(?:[ _.-]?(\d{2})){4}$/;

Ou bien, pour utiliser l'autre façon de créer une regex :

var regexTel = new RegExp("^(0[1-68])(?:[ _.-]?(\\d{2})){4}$");

Et comme vous mourez d'envie de la tester, voici un petit script pour demander un numéro et le tester. :p

var regexTel = /^(0[1-68])(?:[ _.-]?(\d{2})){4}$/;
var numeroTel = prompt("Quel est votre numéro de téléphone ?");
if(regexTel.test(numeroTel))
     alert("Votre numéro semble correct");
else
     alert("Ce n'est pas un numéro de téléphone (français) valide");
L'adresse e-mail

Après l'exemple du numéro de téléphone, vérifier une adresse e-mail ne devrait pas vous poser trop de problèmes...

Si on récapitule, une adresse e-mail, c'est

  • des caractères : lettres, chiffres, points et tirets (hauts ou bas),

  • un symbole "arobase" @,

  • des caractères : comme au début, mais en minuscules ; au moins deux,

  • un point,

  • des caractères : de 2 à 4 lettres minuscules.

On a donc notre regex sans trop de difficultés :
/^[a-zA-Z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,4}$/

Utiliser une regex

reg.test(str)

Renvoie true si la chaine vérifie le motif, false sinon.

reg.exec(str)

Cherche la première expression vérifiant le motif, et renvoie un tableau contenant :

  • dans la première case (d'indice 0), l'expression qui vérifie le motif,

  • dans les cases suivantes (à partir de l'indice 1), les sous-chaînes capturées via les parenthèses.

str.match(reg)

Renvoie un tableau :

  • s'il n'y a pas le flag "g" : le tableau contient la première expression qui satisfait le motif, et les captures (même résultat que reg.exec(str)) ;

  • s'il y a le flag "g" : le tableau contient toutes les expressions satisfaisant le motif (mais sans les captures).

str.search(reg)

Renvoie la position de la première expression qui vérifie le motif.

str.replace(reg, str2)

Remplace les expressions vérifiant le motif par la chaine str2 (uniquement la première s'il n'y a pas le flag "g", toutes s'il y est) ; le résultat est renvoyé.

La valeur capturée par la n-ième parenthèse (n étant un numéro, plus grand ou égal à 1) est accessible via $n.

Exemple : affichera "Le grooos chat griiis est très graaas !"

var regex = /gr([aio])s/g;
var chaine = "Le gros chat gris est très gras !";
var resultat = chaine.replace(regex, "gr$1$1$1s");
alert(resultat);

str.split(reg)

Découpe la chaine aux endroits où le motif est vérifié. Les éléments capturés via les parenthèses sont rajoutés au découpage.

Exemple pour scinder une chaîne là où il y a des signes de ponctuation, en conservant ces signes (pour rappel, \s = caractère blanc) :

var regex = /\s?([.,:;])\s?/;
var chaine = "Ceci est un test : il est destiné à tester des regex ; à rien d'autre, rien.";
var resultat = chaine.split(regex);

Voici le résultat obtenu :

Citation : Contenu du tableau

resultat[0] : "Ceci est un test"
resultat[1] : ":"
resultat[2] : "il est destiné à tester des regex"
resultat[3] : ";"
resultat[4] : "à rien d'autre"
resultat[5] : ","
resultat[6] : "rien"
resultat[7] : "."
resultat[8] : "" (car il n'y a rien après le point)

J'espère que vous avez tenu le coup ;) .
Si tout est un peu flou pour vous, revenez-y un peu plus tard, lorsque vous serez plus familiarisés avec les objets JS.

Ce sujet est certes difficile, mais les regex sont des outils vraiment puissants : ça vaut le coup de s'y intéresser.

Exemple de certificat de réussite
Exemple de certificat de réussite