Avant-propos |
Introduction |
Règles de base des Expressions Régulières |
En premier lieu, nous allons étudier les 2 caractères spéciaux que sont ^ et $. Le premier sert à définir le début d'une chaîne, le second la fin :
Nous voyons dans ce dernier exemple que si l'on n'utilise pas les caractères ^ et $, cela indique que le motif (pattern) peut se trouver n'importe où dans la chaîne.
Nous disposons aussi des symboles *, +, et ? pour exprimer le nombre de fois où un caractère ou une séquence de caractères peut apparaître dans la chaîne. Voici leur signification : * => "zero occurrence ou plus", + => "une occurrence ou plus", et ? => "zéro ou une occurrence.". Quelques exemples :
Les accolades { } vont nous permettre d'indiquer plus précisement le nombre d'occurrences possibles :
Notez que vous devez obligatoirement spécifier la première valeur de l'intervalle (i.e, la syntaxe "{0,2}" est correcte, mais pas "{,2}"). Vous aurez remarqué aussi que les symboles *, +, et ? ont la même signification que les intervalles "{0,}", "{1,}", et "{0,1}".
Pour définir une séquence de caractères, il suffit d'utiliser les parenthèses ( ) :
Nous disposons aussi du symbole | comme opérateur booléen OU :
Le point . représente un caractère unique :
Les crochets [ ] permettent eux de spécifier quels sont les caractères autorisés à un endroit précis de la chaîne :
Vous pouvez aussi indiquer les séquences que vous voulez exclure en utilisant le symbole ^ en premier caractère d'une expression entre crochets [ ] (i.e., "%[^a-zA-Z]%" pour les chaînes contenant un caractère qui n'est pas une lettre entre 2 symboles %).
Pour pouvoir utiliser dans une expression régulière les caractères spéciaux "^.[$()|*+?{\" en tant que caractères 'normaux', il faut les faire précéder d'un antislash \. Comme l'antislash est lui-même un caractère spécial de PHP, il faut aussi le faire précéder d'un antislash ! Ce qui nous donne par exemple pour l'expression régulière suivante "(\$|£)[0-9]+" : ereg("(\\$|£)[0-9]+",$chaine) (d'ailleurs, quel genre de chaînes permet-elle de valider ?).
Toutefois, sachez que les expressions entre crochets ne répondent pas à cette règle. Entre crochets, tous les caractères spéciaux, y compris l'antislash, perdent leur 'pouvoir spécial' (i.e., "[*\+?{}.]" correspond aux caractères *, \, +, etc.).
Et comme nous l'indiquent les pages du manuel : "pour inclure le caractère ] dans la liste, placez le en premier (après éventuellement un ^). Pour include le caractère -, placez en première ou dernière position."
Valider des valeurs monétaires |
Nous allons maintenant mettre en application ce que nous venons d'apprendre sur un cas pratique : une expression régulière qui permet de vérifier que l'utilisateur saisi un montant. Un montant (au format US) peut s'écrire de 4 manières acceptables : "10000.00", et "10,000.00", et sans les cents, "10000", et "10,000". Nous pouvons commencer par :
^[1-9][0-9]*$
Ce qui nous permet de valider un nombre qui ne commence pas par 0. La chaîne "0" ne passe donc pas le test. Voici la solution :
^(0|[1-9][0-9]*)$
"Seulement un 0, OU tout nombre qui ne commence pas par un 0". Nous pouvons aussi autoriser un signe moins devant le nombre :
^(0|-?[1-9][0-9]*)$
Ce qui signifie : "Seulement un 0, OU un signe moins optionnel puis tout nombre qui ne commence pas par un 0". Bon, soyons moins strict, et laissons l'utilisateur commencer son nombre par un zéro s'il le souhaite. Supprimons aussi le signe moins, puisqu'il s'agit de valider une chaîne représentant une quantité d'argent. Ce que nous pouvons faire par contre, c'est dire qu'il peut y avoir une partie décimale (optionnelle) :
^[0-9]+(\.[0-9]+)?$
Ce qui signifie qu'un point doit toujours être suivi d'au moins un chiffre. Donc, "10." ne sera pas validé, alors que "10" and "10.2" le seront.
^[0-9]+(\.[0-9]{2})?$
Nous demandons maintenant qu'il y ait exactement 2 décimales après le point. Si vous pensez que c'est trop restrictif, utilisez plutôt :
^[0-9]+(\.[0-9]{1,2})?$
Cela permet à l'utilisateur de ne taper qu'une décimale s'il le souhaite. Pour les virgules séparant les milliers, nous pouvons écrire :
^[0-9]{1,3}(,[0-9]{3})*(\.[0-9]{1,2})?$
"Une séquence de 1 à 3 chiffres suivi par zéro, une ou plusieurs séquences de 1 virgule et 3 chiffres". Facile non ?! Rendons les virgules optionnelles :
^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(\.[0-9]{1,2})?$
Voilà. N'oubliez pas que le + doit être remplacé par une * si vous voulez autoriser la saisie de chaînes vides. Et n'oubliez pas non plus de doubler l'antislash au moment d'appeler une fonction PHP (c'est une erreur courante). Maintenant que la chaîne est validée, nous pouvons supprimer les virgules avec str_replace(",", "", $montant) et convertir (par un cast) la valeur en double afin d'entreprendre les calculs.
Valider les adresses E-mail |
Etudions maintenant le cas des adresses e-mail. Une adresse e-mail se décompose en 3 parties : le nom de l'utilisateur POP3 (tout ce qui se trouve à gauche du caractère @), le caractère @, et le nom du serveur (le reste). Le nom de l'utilisateur peut contenir des lettres minuscules ou majuscules, des chiffres, des points (.), des signes moins (-), et des underscores (_). Idem pour le nom du serveur, sauf qu'il ne doit pas contenir de caractères _ (underscore).
D'autre part, le nom de l'utilisateur ne peut pas commencer ni finir par un point. Il en va de même pour le serveur. Il ne peut pas y avoir non plus plusieurs points consécutifs. On doit pouvoir trouver au moins un caractère entre 2 points. Voyons maintenant comment écrire cette expression régulière :
^[_a-zA-Z0-9-]+$
Cela ne permet pas encore d'autoriser le point. Essayons ce qui suit :
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*$
Cela signifie : "au moins un caractère valide suivi par zéro, une ou plusieurs séquences constituées d'un point suivi de un ou plusieurs caractères valides".
Pour simplifier un peu les choses, nous pouvons utiliser l'expression ci-dessous avec la fonction eregi(), qui n'est pas sensible à la casse (a=A, b=B, ...), contrairement à la fonction ereg(). C'est pourquoi nous n'avons plus besoin de précisier l'intervalle "A-Z" puisque "a-z" lui est équivalent :
^[_a-z0-9-]+(\.[_a-z0-9-]+)*$
Pour le nom du serveur, nous faisons la même chose, sans les underscores :
^[a-z0-9-]+(\.[a-z0-9-]+)*$
Pour terminer, nous pouvons joindre les 2 expressions en les séparant par le caractère @. Par contre dans le deuxième membre nous exigeons la présence d'au moins 1 point suivi de plusieurs caractères, en remplaçant * par + (juste avant le $) :
^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)+$
Autres utilisations |
ereg() and eregi() possèdent des fonctionnalités particulières permettant d'extraire certains éléments d'une chaîne . Par exemple, pour obtenir le nom de fichier d'un chemin ou d'une URL, nous pouvons écrire :
ereg("([^\\/]*)$", $pathOrUrl, $regs); echo $regs[1];
ereg_replace() and eregi_replace() sont aussi très utiles : supposons que vous vouliez séparer tous les mots d'une chaîne par une virgule :
ereg_replace("[ \n\r\t]+", ",", trim($str));
Quelques exercices |
Voilà maintenant de quoi vous occuper quelques temps :
Liens |