Breadcrumb
Last updated on Tuesday, August 2, 2016
  • 30 hours
  • Easy

Free online content available in this course.

Videos available in this course

Paperback available in this course

eBook available in this course.

Certificate of achievement available at the end this course

You can get support and mentoring from a private teacher via videoconference on this course.

Got it!

Les expressions régulières (partie 1/2)

Log in or subscribe to enjoy all this course has to offer!

Vous avez toujours rêvé d'apprendre à parler chinois ?

Ça tombe bien ! Dans ce chapitre, je vais vous apprendre à écrire quelque chose comme ceci :

#(((https?|ftp)://(w{3}\.)?)(?<!www)(\w+-?)*\.([a-z]{2,4}))#

Croyez-moi si vous voulez, mais ce charabia imprononçable… eh bien ça veut vraiment dire quelque chose ! Si, si, je vous jure ! ;-)

Les expressions régulières constituent un système très puissant et très rapide pour faire des recherches dans des chaînes de caractères (des phrases, par exemple). C'est une sorte de fonctionnalité Rechercher / Remplacer très poussée, dont vous ne pourrez plus vous passer une fois que vous saurez vous en servir.

Les expressions régulières vont nous permettre d'effectuer des recherches et des remplacements poussés dans des textes. Voici quelques exemples pratiques de ce que vous serez en mesure de faire.

  • Vérifier automatiquement si l'adresse e-mail entrée par le visiteur a une forme valide (comme « dupont@free.fr »).

  • Modifier une date que vous avez au format américain (08-05-1985) pour la mettre dans le bon ordre en français (05/08/1985).

  • Remplacer automatiquement toutes les adresses « http:// » par des liens cliquables, comme cela se fait sur certains forums.

  • Ou encore créer votre propre langage simplifié à partir du HTML, comme le fameux bbCode ([b][/b]…).

Ouvrez grand vos oreilles et attachez vos ceintures !

Où utiliser une regex ?

POSIX ou PCRE ?

Bonne nouvelle : vous n'aurez pas à activer quoi que ce soit pour faire des expressions régulières (contrairement à la bibliothèque GD).

Il existe deux types d'expressions régulières, qui répondent aux doux noms de :

  • POSIX : c'est un langage d'expressions régulières mis en avant par PHP, qui se veut un peu plus simple que PCRE (ça n'en reste pas moins assez complexe). Toutefois, son principal et gros défaut je dirais, c'est que ce « langage » est plus lent que PCRE ;

  • PCRE : ces expressions régulières sont issues d'un autre langage (le Perl). Considérées comme un peu plus complexes, elles sont surtout bien plus rapides et performantes.

PHP propose donc de choisir entre POSIX et PCRE. Pour ma part, le choix est tout fait : nous allons étudier PCRE.
Rassurez-vous, ce n'est pas beaucoup plus compliqué que POSIX, mais ça a l'avantage d'être très rapide. Et à notre niveau de PHP, ce qui nous intéresse justement c'est la rapidité.

Les fonctions qui nous intéressent

Nous avons donc choisi PCRE. Il existe plusieurs fonctions utilisant le « langage PCRE » et qui commencent toutes par preg_ :

  • preg_grep ;

  • preg_split ;

  • preg_quote ;

  • preg_match ;

  • preg_match_all ;

  • preg_replace ;

  • preg_replace_callback.

Pour éviter de faire trop de théorie, on va commencer, pour s'entraîner, à utiliser une de ces fonctions : preg_match.

preg_match

En utilisant cette fonction, vous pourrez vous exercer en même temps que moi et voir petit à petit si vous avez compris le principe du langage PCRE.
Il faut juste savoir que cette fonction renvoie un booléen : VRAI ou FAUX (true ou false en anglais). Elle renvoie true (vrai) si elle a trouvé le mot que vous cherchiez dans la chaîne, false (faux) si elle ne l'a pas trouvé.

Vous devez lui donner deux informations : votre regex (c'est le petit nom qu'on donne à « expression régulière ») et la chaîne dans laquelle vous faites une recherche.
Voici par exemple comment on peut s'en servir, à l'aide d'une condition if :

<?php
if (preg_match("** Votre REGEX **", "Ce dans quoi vous faites la recherche"))
{
	echo 'Le mot que vous cherchez se trouve dans la chaîne';
}
else
{
	echo 'Le mot que vous cherchez ne se trouve pas dans la chaîne';
}
?>

À la place de « ** Votre REGEX ** », vous taperez quelque chose en langage PCRE, comme ce que je vous ai montré au début de ce chapitre :

#(((https?|ftp)://(w{3}\.)?)(?<!www)(\w+-?)*\.([a-z]{2,4}))#

C'est justement ceci qui nous intéresse, c'est sur ça que nous allons nous pencher par la suite.
Parce que – au cas où vous ne l'auriez pas remarqué – ce truc-là n'est franchement pas évident à lire… Et le chinois a l'air tout simple à côté !

Des recherches simples

On va commencer par faire des recherches très simples et très basiques. Normalement, vous ne devriez pas avoir trop de mal à suivre pour l'instant, c'est quand on mélangera tout après que ça se compliquera.

Première chose importante à savoir : une regex (Expression régulière) est toujours entourée de caractères spéciaux appelés délimiteurs.
On peut choisir n'importe quel caractère spécial comme délimiteur, et pour éviter de tourner en rond trop longtemps, je vais vous en imposer un : le dièse !
Votre regex se trouve alors entourée de dièses, comme ceci :

#Ma regex#

Euh, mais à quoi servent les dièses, puisque de toute façon la regex est entourée par des guillemets dans la fonction PHP ?

Parce que si on veut, on peut utiliser des options. On ne va pas parler des options tout de suite car on n'en a pas besoin pour commencer, mais sachez que ces options se placent après le second dièse, comme ceci :

#Ma regex#Options

À la place de « Ma regex », vous devez mettre le mot que vous recherchez.
Prenons un exemple : vous aimeriez savoir si une variable contient le mot « guitare ». Il vous suffit d'utiliser la regex suivante pour faire la recherche :

#guitare#

Dans un code PHP, ça donne :

<?php
if (preg_match("#guitare#", "J'aime jouer de la guitare."))
{
    echo 'VRAI';
}
else
{
    echo 'FAUX';
}
?>

Si vous exécutez ce code, vous verrez qu'il affiche VRAI parce que le mot « guitare » a été trouvé dans la phrase « J'aime jouer de la guitare. ».

Retenez bien ce petit bout de code. Nous allons le garder un moment en changeant parfois la regex, parfois la phrase dans laquelle on fait la recherche.
Pour que vous compreniez bien comment les regex se comportent, je vais vous présenter les résultats dans un tableau, comme ceci :

Chaîne

Regex

Résultat

J'aime jouer de la guitare.

#guitare#

VRAI

J'aime jouer de la guitare.

#piano#

FAUX

O.K., c'est compris jusque-là ? ;-)
On a trouvé le mot « guitare » dans la première phrase, mais pas « piano » dans la seconde.
Jusque-là c'est facile, mais je ne vais pas tarder à compliquer !

Et tu casses, tu casses, tu casses…

Il y a quelque chose qu'il faut que vous sachiez : les regex font la différence entre majuscules et minuscules ; on dit qu'elles sont « sensibles à la casse ». Tenez, regardez ces deux regex par exemple :

Chaîne

Regex

Résultat

J'aime jouer de la guitare.

#Guitare#

FAUX

J'aime jouer de la guitare.

#GUITARE#

FAUX

Comment faire si on veut que nos regex ne fassent plus la différence entre majuscules et minuscules ?
On va justement utiliser une option. C'est la seule que vous aurez besoin de retenir pour le moment. Il faut rajouter la lettre « i » après le 2e dièse, et la regex ne fera plus attention à la casse :

Chaîne

Regex

Résultat

J'aime jouer de la guitare

#Guitare#i

VRAI

Vive la GUITARE !

#guitare#i

VRAI

Vive la GUITARE !

#guitare#

FAUX

Dans le dernier exemple, je n'ai pas mis l'option « i » alors on m'a répondu FAUX.
Mais dans les autres exemples, vous pouvez voir que le « i » a permis de ne plus faire la différence entre majuscules et minuscules. ;-)

Le symbole OU

On va maintenant utiliser le symbole OU, que vous avez déjà vu dans le chapitre sur les conditions : c'est la barre verticale « | ».
Grâce à elle, vous allez pouvoir laisser plusieurs possibilités à votre regex. Ainsi, si vous tapez :

#guitare|piano#

… cela veut dire que vous cherchez soit le mot « guitare », soit le mot « piano ». Si un des deux mots est trouvé, la regex répond VRAI.
Voici quelques exemples :

Chaîne

Regex

Résultat

J'aime jouer de la guitare.

#guitare|piano#

VRAI

J'aime jouer du piano.

#guitare|piano#

VRAI

J'aime jouer du banjo.

#guitare|piano#

FAUX

J'aime jouer du banjo.

#guitare|piano|banjo#

VRAI

Dans le dernier exemple, j'ai mis deux fois la barre verticale. Cela signifie que l'on recherche guitare OU piano OU banjo.

Vous suivez toujours ?
Parfait !
On peut maintenant voir les problématiques de début et de fin de chaîne, et ensuite on pourra passer à la vitesse supérieure.

Début et fin de chaîne

Les regex permettent d'être très très précis, vous allez bientôt vous en rendre compte.
Jusqu'ici en effet le mot pouvait se trouver n'importe où. Mais supposons que l'on veuille que la phrase commence ou se termine par ce mot.

Nous allons avoir besoin des deux symboles suivants, retenez-les :

  • ^ (accent circonflexe) : indique le début d'une chaîne ;

  • $ (dollar) : indique la fin d'une chaîne.

Ainsi, si vous voulez qu'une chaîne commence par « Bonjour », il faudra utiliser la regex :

#^Bonjour#

Si vous placez le symbole « ^ » devant le mot, alors ce mot devra obligatoirement se trouver au début de la chaîne, sinon on vous répondra FAUX.

De même, si on veut vérifier que la chaîne se termine par « zéro », on écrira cette regex :

#zéro$#

Compris ? Voici une série de tests pour que vous voyiez bien comment ça fonctionne :

Chaîne

Regex

Résultat

Bonjour petit zéro

#^Bonjour#

VRAI

Bonjour petit zéro

#zéro$#

VRAI

Bonjour petit zéro

#^zéro#

FAUX

Bonjour petit zéro !!!

#zéro$#

FAUX

Simple, non ?
Dans le dernier cas ça ne fonctionne pas, car la chaîne ne se termine pas par « zéro » mais par « !!! ». Donc forcément, on nous répond FAUX…

Les classes de caractères

Jusqu'ici, vous avez pu faire des recherches assez simples, mais encore rien de vraiment extraordinaire. L'outil de recherche de Word fait bien tout cela, après tout.
Mais rassurez-vous, les regex sont bien plus riches (et complexes) que l'outil de recherche de Word, vous allez voir.

Grâce à ce qu'on appelle les classes de caractères, on peut faire varier énormément les possibilités de recherche.

Tout cela tourne autour des crochets. On place une classe de caractères entre crochets dans une regex.
Cela nous permet de tester beaucoup de possibilités de recherche à la fois, tout en étant très précis.

Des classes simples

Ne tournons pas en rond plus longtemps, et regardons attentivement cette regex :

#gr[io]s#

Entre crochets, c'est ce qu'on appelle une classe de caractères. Cela signifie qu'une des lettres à l'intérieur peut convenir.
Dans le cas présent, notre regex reconnaît deux mots : « gris » et « gros ». C'est un peu comme le OU qu'on a appris tout à l'heure, sauf que ça s'applique ici à une lettre et non pas à un mot.

D'ailleurs, si vous mettez plusieurs lettres comme ceci :

#gr[ioa]s#

Cela signifie « i » OU « o » OU « a ». Donc notre regex reconnaît les mots « gris », « gros » et « gras » !
Allez, on se fait quelques exemples :

Chaîne

Regex

Résultat

La nuit, tous les chats sont gris

#gr[aoi]s#

VRAI

Berk, c'est trop gras comme nourriture

#gr[aoi]s#

VRAI

Berk, c'est trop gras comme nourriture

#gr[aoi]s$#

FAUX

Je suis un vrai zéro

#[aeiouy]$#

VRAI

Je suis un vrai zéro

#^[aeiouy]#

FAUX

Je suppose que vous comprenez les deux premières regex. Mais je pense que vous auriez besoin d'explications sur les trois dernières.

  • Pour « Berk, c'est trop gras comme nourriture », j'ai utilisé cette fois la regex #gr[aoi]s$#. Si vous avez bien suivi ce que je vous ai dit tout à l'heure, ça veut dire que notre chaîne doit se terminer par « gris », « gras » ou « gros ». Or ici le mot est au milieu, donc on nous répond FAUX. Essayez de le mettre à la fin et vous verrez que ça marche.

  • Ensuite « Je suis un vrai zéro » avec la regex #[aeiouy]$#. Celle-ci signifie que notre regex doit se terminer par une voyelle (aeiouy). Ça tombe bien, la dernière lettre de la chaîne est la lettre « o », donc on nous répond VRAI.

  • Enfin, même chaîne mais avec la regex #^[aeiouy]#. Cette fois, la chaîne doit commencer par une voyelle (en minuscule, en plus). Or la chaîne commence par « J », donc la réponse est FAUX !

Ça va, je ne vous ai toujours pas perdus en route ?
Si à un moment vous sentez que vous avez décroché, n'hésitez pas à relire un peu ce qui se trouve au-dessus, ça ne vous fera pas de mal.

Les intervalles de classe

C'est à partir de ce moment-là que les classes devraient commencer à vous bluffer.

Grâce au symbole « - » (le tiret), on peut autoriser toute une plage de caractères.
Par exemple, tout à l'heure on a utilisé la classe [aeiouy]. O.K., ce n'est pas trop long.
Mais que dites-vous de la classe [abcdefghijklmnopqrstuvwxyz] ? Tout ça pour dire que vous voulez qu'il y ait une lettre ?

J'ai mieux ! ;-)
Vous avez le droit d'écrire : [a-z] ! Avouez que c'est plus court ! Et si vous voulez vous arrêter à la lettre « e », pas de problème non plus : [a-e].
En plus, ça fonctionne aussi avec les chiffres : [0-9]. Si vous voulez plutôt un chiffre entre 1 et 8, tapez : [1-8].

Encore mieux ! Vous pouvez écrire deux plages à la fois dans une classe : [a-z0-9]. Cela signifie « N'importe quelle lettre (minuscule) OU un chiffre ».

Bien entendu, vous pouvez aussi autoriser les majuscules sans passer par les options comme on l'a fait tout à l'heure. Ça donnerait : [a-zA-Z0-9]. C'est donc une façon plus courte d'écrire :

[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789].

Faisons quelques tests, voulez-vous ?

Chaîne

Regex

Résultat

Cette phrase contient une lettre

#[a-z]#

VRAI

cette phrase ne comporte ni majuscule ni chiffre

#[A-Z0-9]#

FAUX

Je vis au 21e siècle

#^[0-9]#

FAUX

<h1>Une balise de titre HTML</h1>

#<h[1-6]>#

VRAI

Le dernier exemple est particulièrement intéressant car on se dirige doucement vers la pratique. On y vérifie justement si la chaîne comporte une balise HTML de titre (<h1> ou <h2>, etc., jusqu'à <h6>).

Et pour dire que je n'en veux pas ?

Si vous ne voulez PAS des caractères que vous énumérez dans votre classe, vous devrez placer le symbole « ^ » au début de la classe.

Mais ?!
Je croyais que ce caractère servait à indiquer le début d'une chaîne ?

Oui, mais si vous le placez à l'intérieur d'une classe, il sert à dire que vous ne VOULEZ PAS de ce qui se trouve à l'intérieur de cette classe.

Ainsi, la regex suivante :

#[^0-9]#

… signifie que vous voulez que votre chaîne comporte au moins un caractère qui ne soit pas un chiffre.

Maintenant, je fais chauffer vos cervelles (tableau suivant).

Chaîne

Regex

Résultat

Cette phrase contient autre chose que des chiffres

#[^0-9]#

VRAI

cette phrase contient autre chose que des majuscules et des chiffres

#[^A-Z0-9]#

VRAI

Cette phrase ne commence pas par une minuscule

#^[^a-z]#

VRAI

Cette phrase ne se termine pas par une voyelle

#[^aeiouy]$#

FAUX

ScrrmmmblllGnngngnngnMmmmmffff

#[^aeiouy]#

VRAI

Je vous conseille de faire une petite pause parce que ça ne va vraiment pas s'arranger par la suite ! Nous allons maintenant découvrir le rôle des quantificateurs qui vont nous permettre de gérer les répétitions.

Les quantificateurs

Les quantificateurs sont des symboles qui permettent de dire combien de fois peuvent se répéter un caractère ou une suite de caractères.
Par exemple, pour reconnaître une adresse e-mail comme francois@free.fr, il va falloir dire : « Elle commence par une ou plusieurs lettres, suivie(s) d'une @ (arobase), suivie de deux lettres au moins, elles-mêmes suivies d'un point, et enfin de deux à quatre lettres (pour le .fr, .com, mais aussi .info(Eh oui, ça existe !).

Bon : pour le moment, notre but n'est pas d'écrire une regex qui permet de savoir si l'adresse e-mail rentrée par le visiteur a la bonne forme (c'est encore trop tôt). Mais tout ça pour vous dire qu'il est indispensable de savoir indiquer combien de fois une lettre peut se répéter !

Les symboles les plus courants

Vous devez retenir trois symboles :

    • ? (point d'interrogation) : ce symbole indique que la lettre est facultative. Elle peut y être 0 ou 1 fois.

Ainsi, #a?# reconnaît 0 ou 1 « a » ;

    • + (signe plus) : la lettre est obligatoire. Elle peut apparaître 1 ou plusieurs fois.

Ainsi, #a+# reconnaît « a », « aa », « aaa », « aaaa », etc. ;

    • * (étoile) : la lettre est facultative. Elle peut apparaître 0, 1 ou plusieurs fois.

Ainsi, #a*# reconnaît « a », « aa », « aaa », « aaaa », etc. Mais s'il n'y a pas de « a », ça fonctionne aussi !

Vous pouvez donc autoriser la répétition d'une lettre. Je viens de vous montrer le cas pour « chien ». Mais on peut aussi s'en servir pour une lettre au milieu du mot, comme ceci :

#bor?is#

Ce code reconnaîtra « boris » et « bois » !

Et si je veux que ce soient deux lettres ou plus qui se répètent, comment je fais ?

Il faut utiliser des parenthèses. Par exemple, si on veut reconnaître « Ayayayayayay » (le cri de guerre de Speedy Gonzales !), on devra taper la regex suivante :

#Ay(ay)*#
Ce code reconnaîtra « Ay », « Ayay », « Ayayay », « Ayayayay », « Ouïe Aïe Aïe » (non, je rigole pour le dernier).

Autre bonne nouvelle : vous pouvez mettre un quantificateur après une classe de caractères (vous savez, avec les crochets !). Ainsi #[0-9]+# permet de reconnaître n'importe quel nombre, du moment qu'il y a au moins un chiffre !

Faisons quelques tests pour bien rentrer ça dans nos têtes (tableau suivant).

Chaîne

Regex

Résultat

eeeee

#e+#

VRAI

ooo

#u?#

VRAI

magnifique

#[0-9]+#

FAUX

Yahoooooo

#^Yaho+$#

VRAI

Yahoooooo c'est génial !

#^Yaho+$#

FAUX

Blablablablabla

#^Bla(bla)*$#

VRAI

Les derniers exemples sont très intéressants. La regex #^Yaho+$# signifie que la chaîne doit commencer et finir par le mot « Yahoo ». Il peut y avoir un ou plusieurs « o ». Ainsi « Yaho », « Yahoo », « Yahooo », etc. marchent… Mais vous ne devez rien mettre avant ni après, car j'ai indiqué que c'était un début ET une fin de chaîne avec ^ et $.

Enfin, la dernière regex autorise les mots « Bla », « Blabla », « Blablabla », etc. Je me suis servi des parenthèses pour indiquer que « bla » peut être répété 0, 1 ou plusieurs fois.

Ça commence à faire mal à la tête, n'est-ce pas ?

Être plus précis grâce aux accolades

Parfois on aimerait indiquer que la lettre peut être répétée quatre fois, ou de quatre à six fois… bref, on aimerait être plus précis sur le nombre de répétitions.
C'est là qu'entrent en jeu les accolades. Vous allez voir : si vous avez compris les derniers exemples, ça va vous paraître tout simple.

Il y a trois façons d'utiliser les accolades.

  • {3} : si on met juste un nombre, cela veut dire que la lettre (ou le groupe de lettres s'il est entre parenthèses) doit être répétée 3 fois exactement.
    #a{3}# fonctionne donc pour la chaîne « aaa ».

  • {3,5} : ici, on a plusieurs possibilités. On peut avoir la lettre de 3 à 5 fois.
    #a{3,5}# fonctionne pour « aaa », « aaaa », « aaaaa ».

  • {3,} : si vous mettez une virgule, mais pas de 2e nombre, ça veut dire qu'il peut y en avoir jusqu'à l'infini. Ici, cela signifie « 3 fois ou plus ».
    #a{3,}# fonctionne pour « aaa », « aaaa », « aaaaa », « aaaaaa », etc. Je ne vais pas tous les écrire, ça serait un peu long.

On se fait quelques exemples, histoire de se dire qu'on est prêts (tableau suivant) ?

Chaîne

Regex

Résultat

eeeee

#e{2,}#

VRAI

Blablablabla

#^Bla(bla){4}$#

FAUX

546781

#^[0-9]{6}$#

VRAI

Voilà un sacré paquet d'ingurgité, dites-moi !
Allez, on va s'arrêter là et faire une bonne pause parce que… dans le prochain chapitre, on mélange tout ce qu'on vient d'apprendre !

En résumé

  • Les expressions régulières sont des outils de recherche et de remplacement de texte très avancés qui permettent d'effectuer des recherches très précises, pour vérifier par exemple que le texte saisi par l'utilisateur correspond bien à la forme d'une adresse e-mail ou d'un numéro de téléphone.

  • La fonction preg_match vérifie si un texte correspond à la forme décrite par une expression régulière.

  • Une expression régulière est délimitée par un symbole (par exemple le dièse #).

  • Les classes de caractères permettent d'autoriser un grand nombre de symboles (lettres et chiffres) selon un intervalle.

  • Les quantificateurs permettent d'exiger la répétition d'une chaîne de texte un certain nombre de fois.

Example of certificate of achievement
Example of certificate of achievement