Aller au contenu principal

Expressions régulières

remarque

Les expressions régulières ne sont pas faciles à comprendre au début car elles prennent des formes peu communes et sont donc difficiles à lire.

Les expressions régulières ou RegExp (Regular Expressions en anglais), sont très puissantes pour rechercher et manipuler du texte en utilisant des patterns (en français des motifs).

Les expressions régulières sont nées dans les années 1950 et ont été adoptées dans de nombreux langages de programmation, éditeurs de texte, et outils de traitement de données.

Les expressions régulières sont comme une langue secrète pour dire à l'ordinateur comment reconnaître des séquences de caractères dans un texte.

astuce

Si vous voulez trouver tous les numéros de téléphone dans un document, ou vérifier que l'adresse email saisie dans un formulaire est valide, les RegExp sont vos alliées.

Utiliser les expressions régulières signifie écrire un pattern.

Voici un exemple de pattern très simple : /chat(s?)/i

Un pattern pour vérifier une adresse email

Voici un exemple de pattern : ^[a-zA-Z-]+@[a-zA-Z-]+\.[a-zA-Z]{2,6}$ qui permet de vérifier si la chaîne de caractères est bien une adresse email.

Remarque sur le quantificateur {2,6}

Dans ce pattern ^[a-zA-Z-]+@[a-zA-Z-]+\.[a-zA-Z]{2,6}$, le {2,6} est un quantificateur qui spécifie que le caractère ou le groupe de caractères qui le précède doit apparaître au moins 2 fois et pas plus de 6 fois. Cela s'applique à la partie de l'expression régulière qui précède immédiatement le quantificateur.

Dans ce cas, [a-zA-Z]{2,6} signifie que la partie de l'adresse e-mail qui suit le point (représentant le début du domaine de premier niveau, ou TLD) doit être composée de lettres minuscules (a-z) ou majuscules (A-Z) et doit avoir une longueur d'au moins deux caractères et pas plus de six. Cette longueur correspond aux longueurs courantes des TLD, comme .com, .info, .travel et d'autres.

Il est important de noter que ce pattern est une simplification et ne couvre pas toutes les règles de validation des adresses e-mail définies par les standards Internet. Par exemple, des TLD plus longs ont été introduits et ne seraient pas validés par ce pattern. De plus, des caractères autres que les lettres et le tiret sont également autorisés dans certaines parties d'une adresse e-mail.

Avantage

Avec une seule expression régulière, vous pouvez effectuer des tâches qui, autrement, nécessiteraient des dizaines de lignes de code.

Syntaxe de Base

Un pattern peut être composé :

  • de littéraux
  • de métacaractères
  • d'opérations
  • et de drapeaux.

Littéraux

Les littéraux sont des caractères ordinaires (comme a, 1, !) qui correspondent à eux-mêmes.

Métacaractères

Les métacaractères sont des caractères spéciaux (comme ., *, +, ?, ^, $, (...)) qui ont une signification particulière :

  • . correspond à n'importe quel caractère
  • * indique que le caractère qui le précède peut être présent zéro ou plusieurs fois
  • + : Le signe plus indique que le caractère ou le groupe précédent doit apparaître une ou plusieurs fois.
  • ? : Le point d'interrogation signifie que le caractère ou le groupe précédent est optionnel, c'est-à-dire qu'il peut apparaître zéro ou une fois.
  • ^ : Le caret représente le début d'une chaîne ou d'une ligne, selon les drapeaux utilisés.
  • $ : Le signe dollar correspond à la fin d'une chaîne ou d'une ligne, également dépendant des drapeaux utilisés.
  • (...) : Les parenthèses sont utilisées pour grouper plusieurs caractères en une seule unité et pour capturer les correspondances pour une utilisation ultérieure.

Opérations

  • Classes de caractères : [a-z] correspond à n'importe quelle lettre minuscule.
  • Quantificateurs : {2,4} appliqué après un caractère ou un groupe signifie "apparaît entre 2 et 4 fois".
  • Assertions : ^ et $ sont des ancres qui correspondent respectivement au début et à la fin d'une ligne.

Drapeaux

Les expressions régulières peuvent être modifiées par des drapeaux qui changent leur comportement,

  • comme i pour ignorer la casse,
  • ou g pour rechercher globalement toutes les occurrences.

Rôles du caractère antislash \

Voici les principaux rôles du caractère antislash \ dans les expressions régulières :

  1. Échappement de métacaractères : Si vous voulez rechercher un métacaractère comme un caractère littéral, vous devez le précéder d'un backslash. Par exemple, pour rechercher un point . dans une chaîne, vous devez utiliser \. dans votre expression régulière, car le point seul a la signification spéciale de correspondre à n'importe quel caractère.

  2. Séquences d'échappement spéciales : Il existe des séquences d'échappement qui ont une signification particulière. Par exemple, \d correspond à n'importe quel chiffre, \w correspond à n'importe quel caractère alphanumérique, et \s correspond à n'importe quel caractère d'espace blanc.

  3. Caractères non imprimables : Certains caractères non imprimables peuvent être insérés dans une expression régulière à l'aide de séquences d'échappement, comme \n pour une nouvelle ligne ou \t pour une tabulation.


Un exemple très simple

Imaginons que nous voulons trouver toutes les occurrences du mot "chat" dans un paragraphe, qu'elles soient au singulier ou au pluriel.

$texte = "Le chat chasse les chats.";
$pattern = "/chat(s?)/i";
preg_match_all($pattern, $texte, $matches);
print_r($matches[0]);

Ce code PHP utilise la fonction preg_match_all() pour chercher notre pattern /chat(s?)/i dans la variable $texte.

Remarque sur la fonction preg_match_all()

En PHP, la fonction preg_match_all() est utilisée pour effectuer une recherche de correspondances globale d'une expression régulière dans une chaîne de caractères. Cette fonction est particulièrement utile lorsque vous souhaitez trouver toutes les occurrences d'un motif dans une chaîne et pas seulement la première.

La signature de la fonction preg_match_all() est la suivante :

int preg_match_all ( string $pattern , string $subject , array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]] )

Le troisième paramètre, $matches, est très important car il est utilisé pour stocker les résultats de la recherche. Ce paramètre est passé par référence, ce qui signifie que toute modification apportée au tableau $matches à l'intérieur de la fonction preg_match_all() sera répercutée sur le tableau original passé à la fonction.

Passer un paramètre par référence permet à la fonction de modifier directement la variable originale, plutôt que de travailler avec une copie de celle-ci. Cela peut être très utile pour les fonctions qui doivent retourner des données complexes ou de grandes quantités de données, comme c'est le cas pour les résultats de correspondances d'expressions régulières.

Voici un exemple de l'utilisation de preg_match_all() :

$subject = "L'année 2024 est pleine de surprises. En 2023, beaucoup de choses ont changé.";
$pattern = "/\b(\d{4})\b/";

// Le tableau $matches sera rempli par référence avec les résultats de la recherche
preg_match_all($pattern, $subject, $matches);

print_r($matches);

Dans cet exemple, $matches est passé à preg_match_all() par référence. Après l'exécution de la fonction, $matches contiendra toutes les correspondances trouvées. Si vous inspectez le contenu de $matches après l'appel de la fonction, vous verrez qu'il a été modifié pour contenir les années "2024" et "2023" qui correspondent au motif défini par $pattern.

En résumé, le troisième paramètre de preg_match_all() est crucial car il permet de récupérer toutes les correspondances d'une expression régulière dans une chaîne de caractères, et le fait qu'il soit passé par référence rend la fonction à la fois efficace et puissante pour manipuler des données complexes.

Pour plus d'infos sur la fonction intégrée à PHP : https://www.php.net/manual/fr/function.preg-match-all.php

Pour plus d'infos sur le passage de paramètre par référence en PHP : Par valeur ou par référence

remarque

Le (s?) signifie que la lettre "s" peut être présente ou non, et le i à la fin rend notre recherche insensible à la casse.

Une solution


Un exemple de recherche de texte

Nous allons utiliser une expression régulière pour chercher un mot dans un texte, avec l'éditeur de textes NotePad++ que vous pouvez télécharger à cette adresse : https://notepad-plus-plus.org/.

Voici le texte dans lequel nous allons chercher des mots :

Bonjour, Je suis monsieur Dupond, j'ai 37 ans, j'habite en France et travaille depuis que j'ai 20 ans. Ma passion : écrire des mots ! Et je joue avec les mots, les mats, les mets, les mits, les mots, les muts, Bien-sûr je manipule les mots dans tous les sens. Pour cela j'utilise les expressions régulières. Enfin c'est pas très facile à utiliser. Bonjour l'écriture d'un motif ! Quand je réussis du premier coup, je suis content. Pour me contacter, vous pouvez envoyer un email à contact@dupond.fr ou contact@dupond.com ou bien m'appeler au 06 77 88 99 00. Vius pouvez m'écrire un petit message, ou tout simplement me dire Bonjour. Vous pouvez aussi aller voir mon blog à l'adresse dupond-blog.fr. Cordialement. M. Dupond

Pour commencer :

  1. ouvrez Notepad++
  2. et collez le texte ci-dessus.


Chercher un mot

  1. Cherchez le mot « Bonjour » en début de message (pour le remplacer par le mot « Bonsoir »).
Pour chercher du texte dans Notepad++

Pour chercher du texte dans Notepad++, il suffit d'utiliser la combinaison de touches « CTRL + F »

ou le menu « Recherche » - « Rechercher... »

Voici les 3 occurrences trouvées :

Rechercher uniquement en début d'un paragraphe

Nous souhaitons uniquement trouver le mot « Bonjour » en début d'un paragraphe, pour le remplacer par le mot « Bonsoir », et pas tous les mots « Bonjour ».

Pour cela, nous allons utiliser le pattern : ^Bonjour

  • le symbole « ^ » signifie en début de paragraphe
  • le symbole « $ » signifie en fin de paragraphe.

astuce

Pensez à cocher l'option « Expression régulière » en bas à gauche de la fenêtre de recherche de NotePad++.

  1. Combien d'occurrences trouvez-vous ?
Réponse
astuce

Pour compter le nombre d'occurrences, il suffit de cliquer sur le bouton « Compter » dans la fenêtre de recherche de NotePad++.

Maintenant insérez un retour à la ligne après les mots « ... très facile à utiliser. »

et recherchez le pattern : ^Bonjour

  1. Combien d'occurrences trouvez-vous ?
Réponse

Veuillez effacer le retour à la ligne après les mots « ... très facile à utiliser. », et utilisez la combinaison de touches « CTRL + H » pour remplacer « Bonjour » par « Bonsoir »

Maintenant, faites une recherche en utilisant le pattern Dupond$.

  1. Combien d'occurrences trouvez-vous ?
Réponse
  1. Pourquoi ?
Réponse

Chercher un mot OU un autre mot

Imaginons maintenant que nous voulions rechercher, dans le texte, les mots "Bonjour" et "Dupond", c'est à dire le mot "Bonjour" OU le mot "Dupond".

Pour cela nous devons utiliser la barre verticale |.

Ainsi le pattern suivant va sélectionner toutes les occurrences de Bonjour et Dupond :

Bonjour|Dupond

  1. Combien d'occurrences trouvez-vous ?
Réponse
Rappel

Le symbole « | » signifie OU.

Il est aussi possible de sélectionner les occurrences du mot "Bonjour" se trouvant au début du texte et du mot "Dupond" se trouvant à la fin, ce qui revient à fusionner les 2 patterns que nous venons d'utiliser (en les séparant par une barre verticale).

Voici le nouveau pattern :

^Bonjour|Dupond$

  1. Combien d'occurrences trouvez-vous ?
Réponse
  1. Pourquoi ?
Réponse
Rappel

Le symbole « ^ » signifie en début de paragraphe et le symbole « $ » signifie en fin de paragraphe.


Chercher un ensemble de caractères

Passons maintenant à des patterns un peu plus élaborés, et beaucoup plus puissants, avec les ensembles de caractères.

Voici un pattern à tester :

mats|mets|mits|mots|muts

  1. Combien d'occurrences trouvez-vous ?
Réponse
astuce

Mais il y a plus simple et ce grâce aux ensembles de caractères qui font office, en quelques sortes, de OU en plus courts et plus puissants.

Un ensemble de caractère est délimité par des crochets [] dans lesquels se trouvent les caractères faisant parti du OU.

Ainsi, le pattern suivant :

m[aeiou]ts

est beaucoup plus court que le précédent et sélectionne les mêmes mots.

Ce pattern peut être traduit par la phrase suivante : "sélectionne les parties du texte où il y a un m, suivi d'un a ou un e ou un i ou un o ou un u suivi par ts"

Voici un pattern à tester :

m[aeiou]ts

  1. Combien d'occurrences trouvez-vous ?
Réponse
info

Les ensembles de caractères permettent aussi d'exclure des caractères, grâce à l'accent circonflexe ^.

Voici un autre pattern à tester :

m[^o]ts

  1. Combien d'occurrences trouvez-vous ?
Réponse

Ce pattern peut être traduit par la phrase suivante :

"sélectionne les parties du texte où il y a un m, suivi d'une lettre qui n'est pas un o suivi par ts"

Rappel

Le symbole « ^ » permet d'exclure un ou plusieurs caractères.


Les intervalles

Enfin, imaginons que nous voulions sélectionner tous les mots commençant par un m, suivi de n'importe quelle lettre, suivi d'un t, suivi d'un s.

  1. Quel pattern pensez-vous utiliser ?

Le pattern qui vous vient à l'esprit est probablement celui-ci :

m[abcdefghijklmnopqrstuvwxyz]ts

Ce pattern est long et fastidieux à écrire, surtout que seules les minuscules ont été sélectionnées ! Il nous faut également tenir compte des majuscules...

Heureusement, un moyen plus simple existe pour écrire de tel pattern : cela s'appelle
les intervalles et se note [début intervalle-fin intervalle].

Voici quelques petites exemples d'intervalles :

ExpressionExemplesDescription
[a-z][abcdefghijklmonpqrstuvwxyz]Lettres minuscules de a à z
[A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ]Lettres majuscules de A à Z
[0-9][0123456789]Chiffres de 0 à 9
[a-z0-9][abcdefghijklmonpqrstuvwxyz0123456789]Lettres minuscules de a à z ou chiffres de 0 à 9
attention

Les symboles « [ » et « ] » sont utilisés pour les intervalles de caractères ou de nombres.

Reprenons donc notre pattern et utilisons les intervalles.

  1. Quel pattern utiliser pour compter tous les mots, quelque soit la lettre minuscule à la place du o ?
Réponse
  1. Combien d'occurrences trouvez-vous ?
Réponse

Les ensembles préconçus

Un ensemble préconçu est une façon très simple de représenter des caractères particuliers ou des intervalles.

En voici quelques exemples :

CodeSignificationExemple
.Absolument n'importe quel caractèrea, 1, !
\w[a-zA-Z0-9_]A, 0, _
\d[0-9]0 à 9
\nUn retour à la ligne(retour à la ligne)
\tUne tabulation(tabulation)

Ainsi, ce pattern :

m\wts

sélectionnera les mêmes éléments que celui-ci :

m[a-zA-Z0-9]ts

  1. Combien d'occurrences trouvez-vous, avec le pattern m\wts ?
Réponse
  1. Combien d'occurrences trouvez-vous, avec le pattern m[a-zA-Z0-9]ts ?
Réponse

Les quantificateurs

Nous venons de voir qu'un ensemble de caractères permet de définir de manière très simple les valeurs possible d'un caractère.

Mais qu'en est-il si l'on définit les mêmes valeurs possibles pour plusieurs caractères ?

Par exemple, si l'on veut sélectionner les parties du texte où il y a :

  • un j
  • suivi de 3 lettres minuscules (quelconques)

Est-on obligé d'utiliser un pattern de ce type : j[a-z][a-z][a-z] ?

Non.

Il existe une méthode plus simple qui consiste à utiliser les quantificateurs.

Les quantificateurs sont des caractères qui indiquent le nombre de répétitions du caractère (ou de la suite de caractères) qui le(s) précède(nt).

Le quantificateur peut s'écrire de 4 façons :

  • {mini,maxi} : le nombre de répétitions varie entre le mini et le maxi
  • {min,} : le nombre de répétitions varie entre la valeur mini et l'infini*
  • {,maxi} : le nombre de répétitions varie entre 0 et la valeur maxi
  • {nombre} : le nombre de répétition correspond au nombre
  1. Quel pattern permet de sélectionner les parties du texte où il y a 6 lettres consécutives ?
Réponse
  1. Quel pattern permet de sélectionner les parties du texte où il y a entre 2 et 4 chiffres qui se suivent ?
Réponse
attention

Les symboles { et } permettent de préciser un quantificateur.

Il existe aussi des quantificateurs préconçus. En voici la liste :

SymboleSignificationÉquivalent
*0 ou plusieurs répétitions{0,}
+1 ou plusieurs répétitions{1,}
?0 ou 1 répétition{,1}

L'échappement

Reprenons notre texte et imaginons que l'on veuille y sélectionner les noms de domaine des adresse contact@dupond.fr et contact@dupond.com.

  1. Quel pattern permet de sélectionner les noms de domaine des adresse

contact@dupond.fr et contact@dupond.com ?

Attention, il ne faut pas sélectionner dupond-blo.

Réponse

Si vous avez utilisé le pattern dupond.[a-z]3 sans \ devant . (le point) le texte dupond-blo se retrouve sélectionné.

Ce problème vient alors du point présent dans le pattern car rappelez-vous que le point est un ensemble de caractères préconçus qui représente n'importe quel caractère.

Ici, le point peut représenter :

  • un a,
  • un 2
  • mais aussi un tiret.
Rappel

Le point « . » permet de remplacer un caractère (lettre, chiffre, symbole).

Le point est équivalent à un joker.

Pour faire comprendre que le point présent dans le pattern est bien un point et non pas un ensemble de caractères, il nous faut échapper le point avec le caractère d'échappement qui est l'anti-slash \.

Cet échappement n'est pas seulement valable pour le point, mais pour tous les caractères qui ont, de base, une valeur différente que celle habituelle.

En voici la liste : ^ $ \ | [ ] ( ) ? # ! + * .

Cas pratique

Maintenant que vous possédez d'assez bonnes bases pour comprendre et utiliser les expressions régulières, il est temps de passer à un cas pratique.

Exemple 1 - Vérifier la validité d'un numéro de téléphone

Ce premier exemple consiste à vérifier si un numéro de téléphone est correcte.

Nous allons élaborer une expression régulière pour vérifier la validité du numéro de téléphone.

Voici une suite de numéros de téléphone, avec lesquels nous allons pouvoir tester notre pattern.

06 11 22 33 44
+336 12 34 56 78
+33612345678
061122334
+072805512
+347 85 52 03 89
+337 08 56 345
+347 28 05 512
+3472805512
0611223344
remarque

Afin de tester votre pattern, vous pouvez utiliser NotePad++ ou https://regex101.com/

  1. Quel pattern permet de rechercher deux chiffres qui se suivent ?
Réponse

Afin de rechercher deux chiffres précédés ou non d'un espace, nous allons utiliser l'étoile.

attention

L'étoile permet d'indiquer zéro ou plusieurs occurrences du caractère précédent.

Par exemple, ab* correspond à a, ou ab, ou abb, ou abbb, ou abbbb, abbbbb, abbbbbb, etc.

20) Quel pattern permet de rechercher 2 chiffres précédés ou non d'un espace ?

Réponse

Un numéro de téléphone est composé de 10 chiffres. Ces 10 chiffres sont représentés par 5 blocs de 2 chiffres séparés ou non par des espaces. On peut considérer que le premier bloc est particulier puisque que le 0 (zéro) du début peut être remplacé par le code de la France (+33). Pour cette raison, nous allons pour l'instant rechercher 4 blocs de 2 chiffres précédés ou non d'un espace.

  1. Quel pattern permet de rechercher 4 blocs de 2 chiffres précédés ou non d'un espace ?
Réponse

Ensuite nous allons traiter le premier bloc qui compose un numéro de téléphone. C'est à dire un 0 (zéro) ou le code de la France (+33).

  1. Quel pattern permet de rechercher le 0 ou +33 ?

Attention, le caractère + fait partie de la liste des caractères à échapper : ^ $ \ | [ ] ( ) ? # ! + * .

Réponse

Maintenant nous souhaitons rechercher le 0 ou +33 suivi d'un nombre compris en 1 et 9.

Et afin de créer des groupes de caractères, nous allons ajouter des parenthèses.

Un peu comme les parenthèses utilisées en mathématiques.

  1. Quel pattern permet de rechercher le 0 ou +33 suivi d'un nombre compris en 1 et 9 ?
Réponse

Terminons l'élaboration de notre pattern pour rechercher les numéros français, qui commencent par 0 ou +33 et possédant 9 chiffres sans compter le 0 ou +33.

Rappel

Les symboles « ( » et « ) » permettent de créer un groupe de caractères.

  1. Quel pattern permet de rechercher les numéros français, commençant par 0 ou +33 suivis de 9 chiffres ?
Réponse
remarque

Notre pattern d'expressions régulières est perfectible. Notamment certains numéros ne sont pas traités tel que ceux de la forme 0800 123 456.


Test de mémorisation/compréhension


Quel métacaractère correspond à n'importe quel caractère dans une expression régulière ?


À quoi sert le drapeau 'i' dans une expression régulière ?


Que signifie le quantificateur '{2,4}' dans une expression régulière ?


Quelle fonction PHP permet de rechercher des correspondances d'une expression régulière dans une chaîne ?


Comment écririez-vous une expression régulière qui correspond à 'php' ou 'PHP' ?


Que représente le métacaractère '^' dans une expression régulière ?


Quel est le rôle du métacaractère '$' dans une expression régulière ?


Dans une expression régulière, que spécifie le quantificateur '+' ?


Quelle fonction PHP est utilisée pour remplacer une chaîne trouvée par une expression régulière ?


Comment feriez-vous pour chercher 'http' au début d'une chaîne et 'com' à la fin dans une expression régulière ?



Maintenant que nous avons élaboré un pattern d'expressions régulières, voyons comment l'utiliser avec le langage PHP.

TP - Un script PHP

Consigne : Écrivez un fichier PHP tp-regexp1.php qui vérifie si la chaîne de caractères "Mon numéro est le 01 23 45 67 89." contient un numéro de téléphone français (format 01 23 45 67 89 ou 0123456789).

Votre mission consiste à rédiger le pattern.

// Votre chaîne de test
$texte = "Mon numéro est le 01 23 45 67 89.";
//$texte = "Mon numéro est le 1 23 45 67 89.";
//$texte = "Mon numéro est le +331 23 45 67 89.";

// Votre expression régulière
$pattern = "/ ... /"; //pattern à compléter

// Testez si le pattern correspond à la chaîne
if (preg_match($pattern, $texte)) {
echo "Numéro de téléphone valide trouvé.";
} else {
echo "Aucun numéro de téléphone valide détecté.";
}

Votre pattern va décomposer le numéro en plusieurs parties :

  • partie 1 : vérifier que la chaîne de caractères commence par un zéro suivi d'un chiffre de 1 à 9,
  • partie 2 : vérifier que la partie 1 est suivie par 4 groupes de 2 chiffres (qui peuvent être précédés d'un espace ou non).

Pour exécuter ce script, vous n'avez pas besoin d'un serveur Web.

Vous pouvez utiliser le terminal (ou l'invite de commande) et taper php -f tp-regexp1.php.

Une solution

TP - Un formulaire

Consigne : Écrivez un fichier HTML index.html qui contient plusieurs champs dont un nommé numero dans lequel l'utilisateur saisi son numéro de téléphone.

Une fois le formulaire complété, l'utilisateur clique sur Valider et envoi ses données vers une page traitement.php dans laquelle on les vérifie avant de les entrer dans une base de données.

  1. Quel peut être le code source de notre formulaire en langage HTML du fichier index.html qui affiche un formulaire pour saisir un numéro de téléphone ?

Consignes :

  • Le champ de saisi du numéro de téléphone sera nommé numero.
  • Les données du formulaires HTTP seront envoyées avec la méthode POST.
  • La fonction PHP qui sera utilisée est preg_match()
Une solution
  1. Quel peut être le code source en langage PHP du fichier traitement.php qui affiche si le numéro de téléphone saisi est valide ?
Une solution