Les expressions régulières
Cette séance est un approfondissement facultatif mais utile. Les expressions régulières ont la réputation d'être difficiles pour les débutants : prenez votre temps, avancez pas à pas, et n'hésitez pas à relire chaque exemple plusieurs fois.
Notions théoriques
Qu'est-ce qu'une expression régulière ?
Une expression régulière (ou regex) est un motif (un modèle de texte) qui décrit une manière de reconnaître certaines chaînes de caractères. Elle permet de rechercher, tester ou remplacer du texte selon des règles, plutôt que de comparer une chaîne exacte.
Par exemple, plutôt que de vérifier qu'un texte est exactement égal à "0612345678", une expression régulière permet de vérifier que le texte ressemble à un numéro de téléphone : un 0, suivi de 9 chiffres.
Souvenez-vous de la séance sur les formulaires (0080_PHP_formulaires) : les expressions régulières servent très souvent à valider ce qu'un utilisateur a saisi (email, mot de passe, numéro de téléphone…) avant de l'enregistrer.
Les délimiteurs en PHP
En PHP, un motif de recherche doit toujours être encadré par des délimiteurs, le plus souvent le caractère /.
$motif = "/php/";
Ce motif recherche la présence exacte du texte "php" dans une chaîne.
On peut utiliser d'autres délimiteurs que / (par exemple # ou ~), notamment quand le motif contient lui-même des /. Le caractère de début et de fin doit toujours être le même.
Après le délimiteur de fin, on peut ajouter des modificateurs. Le plus courant est i, pour ignorer la casse (majuscules/minuscules) :
$motif = "/php/i"; // trouve "php", "PHP", "Php"...
Classes de caractères et quantificateurs de base
Une expression régulière se construit avec des symboles spéciaux. En voici les plus utiles pour débuter :
| Symbole | Signification |
|---|---|
\d | un chiffre (équivalent à 0-9) |
\w | un caractère "mot" (lettre, chiffre ou _) |
\s | un espace (espace, tabulation, saut de ligne) |
. | n'importe quel caractère (sauf saut de ligne) |
* | l'élément précédent, 0 fois ou plus |
+ | l'élément précédent, 1 fois ou plus |
? | l'élément précédent, 0 ou 1 fois |
{n,m} | l'élément précédent, entre n et m fois |
Quelques exemples de motifs :
"/\d+/" // un ou plusieurs chiffres à la suite
"/\w+/" // un ou plusieurs caractères de "mot"
"/\d{2,4}/" // entre 2 et 4 chiffres
"/colou?r/" // "color" ou "colour" (le "u" est optionnel)
Les symboles ^ et $ sont appelés des ancres : ^ signifie début de chaîne, $ signifie fin de chaîne. /^\d+$/ vérifie que la chaîne entière est composée uniquement de chiffres, du début à la fin.
Tester et capturer avec preg_match()
La fonction preg_match() teste si un motif est présent dans une chaîne. Elle retourne 1 si le motif est trouvé, 0 sinon.
$texte = "Mon numero est 0612345678";
if (preg_match("/\d+/", $texte)) {
echo "Un nombre a ete trouve.";
}
En ajoutant un troisième paramètre, preg_match() remplit un tableau avec le résultat trouvé :
$texte = "Mon numero est 0612345678";
preg_match("/\d+/", $texte, $resultat);
echo $resultat[0]; // 0612345678
On peut aussi capturer une partie précise du motif en l'entourant de parenthèses (...) :
$texte = "Contact : alice@mail.com";
preg_match("/(\w+)@(\w+\.\w+)/", $texte, $resultat);
echo $resultat[0]; // alice@mail.com (la correspondance complète)
echo $resultat[1]; // alice (le 1er groupe capture)
echo $resultat[2]; // mail.com (le 2eme groupe capture)
Remplacer avec preg_replace()
La fonction preg_replace() fonctionne comme str_replace(), mais avec un motif au lieu d'un texte exact.
$texte = "Le prix est 12 euros et 8 centimes";
$texte = preg_replace("/\d+/", "X", $texte);
echo $texte; // "Le prix est X euros et X centimes"
Tous les groupes de chiffres ont été remplacés par "X", quelle que soit leur longueur.
Exemple concret : valider un format d'email
En combinant les ancres, les classes de caractères et les quantificateurs, on peut construire un motif qui valide un format d'email simple :
$email = "alice@mail.com";
$motif = "/^\w+@\w+\.\w+$/";
if (preg_match($motif, $email)) {
echo "Email valide";
} else {
echo "Email invalide";
}
Ce motif se lit ainsi :
^: début de la chaîne\w+: un ou plusieurs caractères de mot (la partie avant le@)@: le caractère@exact\w+: un ou plusieurs caractères de mot (le nom de domaine)\.: un point exact (le.doit être "échappé" avec\car.seul signifie "n'importe quel caractère")\w+: un ou plusieurs caractères de mot (l'extension, comme "com")$: fin de la chaîne
Ce motif reste simplifié : il ne gère pas tous les formats d'email valides (par exemple les points ou tirets dans la partie avant le @). En pratique, PHP fournit filter_var($email, FILTER_VALIDATE_EMAIL) pour une validation d'email fiable en production. Les expressions régulières restent néanmoins indispensables pour valider des formats plus spécifiques (numéro de téléphone, code postal, référence produit…).
Exemple pratique
<?php
// Validation d'un numero de telephone francais simple : 0 suivi de 9 chiffres
function validerTelephone($numero) {
$motif = "/^0[1-9](\d{2}){4}$/";
return preg_match($motif, $numero) === 1;
}
$numeros = ["0612345678", "061234567", "abcdefghij", "0712345678"];
foreach ($numeros as $numero) {
if (validerTelephone($numero)) {
echo $numero . " est un numero valide\n";
} else {
echo $numero . " est invalide\n";
}
}
// Masquer les 4 derniers chiffres d'un numero de telephone
$numeroMasque = preg_replace("/\d{4}$/", "****", "0612345678");
echo $numeroMasque; // "061234****"
Le motif "/^0[1-9](\d{2}){4}$/" se lit ainsi :
^0: la chaîne commence par le chiffre0[1-9]: suivi d'un chiffre entre 1 et 9 (pas de0en deuxième position)(\d{2}){4}: suivi de 4 fois deux chiffres (soit 8 chiffres au total)$: jusqu'à la fin de la chaîne
Une expression régulière complexe se comprend mieux si on la découpe morceau par morceau, comme ci-dessus. C'est aussi une bonne pratique à adopter en commentaire dans son code, car une regex se relit rarement facilement plusieurs mois après l'avoir écrite.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Dans ce TP, vous allez écrire un petit script de validation de formulaire d'inscription, en utilisant les expressions régulières vues dans cette séance.
- Dans votre répertoire "Documents" créez le répertoire
tp_regex. - Dans ce répertoire créez le fichier
main.php:<?php// Les expressions regulieresprint("Les expressions regulieres \n\n"); - Testez le fonctionnement de ce fichier :
php main.php
Étape 1 — Écrire un motif pour détecter des chiffres
Écrivez un motif qui recherche un ou plusieurs chiffres à la suite, et stockez-le dans une variable $motif.
Stocker un motif dans une variable bien nommée (comme $motifTelephone plutôt que $motif) rend le code plus lisible, surtout quand plusieurs motifs sont utilisés dans le même script.
Étape 2 — Tester une saisie avec preg_match()
En utilisant preg_match(), testez si la chaîne $pseudo contient au moins un chiffre.
Avant d'écrire un motif complexe (comme un email complet), il est utile de tester d'abord un motif simple (comme "contient un chiffre") pour vérifier que l'on comprend bien le comportement de preg_match().
Étape 3 — Capturer une partie du texte
En utilisant des parenthèses de capture, extrayez uniquement les chiffres présents dans la chaîne "Reference produit REF-4521".
Toujours vérifier que preg_match() retourne 1 avant d'utiliser $resultat[1], sinon PHP peut générer une erreur "Undefined array key" si le motif n'a rien trouvé.
Étape 4 — Remplacer un motif avec preg_replace()
En utilisant preg_replace(), remplacez toutes les suites de chiffres présentes dans une chaîne par le texte "[NOMBRE]".
preg_replace() est souvent utilisé pour anonymiser des données dans des journaux (logs) ou des exemples : remplacer un numéro de carte, un email, ou un numéro de téléphone par un texte générique avant de les afficher ou de les stocker.
Étape 5 — Valider un format d'email
Écrivez une fonction validerEmail($email) qui retourne true si l'email respecte le format texte@texte.texte, false sinon.
preg_match() peut retourner 0, 1 ou false (en cas d'erreur dans le motif). Comparer explicitement le résultat à 1 avec === évite les confusions liées à la conversion automatique de type en PHP.
Étape 6 — Valider un numéro de téléphone simple
Écrivez une fonction validerTelephone($numero) qui retourne true si le numéro commence par 0, suivi d'un chiffre entre 1 et 9, puis de 8 chiffres (soit 10 chiffres au total).
Valider avec une expression régulière côté serveur (en PHP) reste indispensable, même si le formulaire HTML fait déjà une validation côté navigateur : un utilisateur malveillant peut toujours contourner la validation du navigateur en envoyant directement une requête.