Les expressions régulières (aussi appellées regexp [1]) sont l’outil idéal pour manipuler des données. Elles permettent, à partir d’un masque (pattern en anglais), de trouver les différentes parties d’une chaîne de caractères correspondant à ce masque.
Une des utilisations les plus courantes est le contrôle d’informations fournies via un formulaire. Les expressions régulières sont, de plus, présentes dans de nombreux langages tels que Perl, C++, Python… On les utilise même dans les fichiers htaccess [2] ou encore les feuilles de style CSS [3].
Nous allons voir dans ce premier article la syntaxe utilisée pour les masques, ainsi que les différents caractères spéciaux utilisables et leur utilité, puis nous mettrons tout cela en pratique avec quelques exemples.
Syntaxe de base
Pour simplifier, une expression régulière est une suite de caractères normaux et de caractères spéciaux. Cette suite de caractère constitue un masque que l’on va ensuite appliquer à une chaîne pour trouver les occurences correspondant à ce masque.
Les deux premiers caractères spéciaux que nous allons étudier sont le chapeau (^
) et le dollar ($
) qui indiquent respectivement le début et la fin d’une chaîne de caractère
^blob
- Une chaîne de caractère commençant par
blob
gulp$
- Une chaîne de caractère se terminant par
gulp
^texte$
- La chaîne
texte
texte
- Une chaîne de caractère contenant la chaîne
texte
Si le masque commence par ^
ou se termine par $
, on dit que le masque est ancré.
Nous allons maintenant voir la signification de l’astérisque (*
, du signe plus (+
) et du point d’interrogation (?
) ainsi que les accolades ({
et }
).
Les accolades permettent d’indiquer une intervalle d’occurences valides. En voici la syntaxe (Le deuxième chiffre est facultatif) puis quelques exemples :
{nombre d'occurences minimum, nombre d'occurences maximum}
a{3}
- Correspond à la chaîne
aaa
a{0,2}
- Correspond à une chaîne vide, à
a
, ou encoreaa
a{1,}
- Correspond à un ou plusieurs
a
Les caractère *
, +
et ?
sont une simplification de cette écriture. *
correspond à zéro occurences ou plus, +
correspond à une occurence ou plus et ?
à zéro ou une occurence.
*
, +
et ?
ont donc respectivement la même signification que {0,}, {1,} et {0,1}
ab*
- Un
a
suivi de zéro ou plusieursb
ab+
- Un
a
suivi de un ou plusieursb
ab?
- Un
a
suivi de zéro ou unb
Note : Le caractère ?
a d’autres significations selon la position dans le masque (nous verrons cela plus loin)
Voyons maintenant le point (.
) et la barre verticale (|
).
On peut considérer le point comme une sorte de joker, il représente n’importe quel caractère. La barre verticale implique une alternative, une possibilité entre deux choix (le motif à sa gauche et celui à sa droite).
a.?
- Un
a
suivi de zéro ou un caractère quelconque ^.{3}a
- Une chaîne commençant par trois caractères quelconque suivis d’un
a
a|b
- Le caractère
a
OU le caractèreb
Nous allons maintenant voir l’utilisation des parenthèses.
Une séquence de caractère entre parenthèses est appellée sous-masque. Les sous-masques sont pratiques pour délimiter une séquence de caractères particulière, et peuvent être imbriqués. De plus, les sous-masques peuvent être utilisées conjointement avec les caractères signifiant le nombre d’occurences
bonjour|soir
- Acceptera les mots
bonjour
ousoir
bon(jour|soir)
- Acceptera les mots
bonjour
oubonsoir
php is (cool|funny)
- Acceptera la chaîne
php is cool
ou la chaînephp is funny
mouarf (arf ){0,2}
- Acceptera la chaîne
mouarf
,mouarf arf
oumouarf arf arf
Voici un tableau des différents caractères spéciaux et leur utilité :
Caractère | Utilité |
---|---|
\ Antislashe |
Caractère d’échappement à usage multiple |
^ Accent circonflexe |
Représente le début d’une chaîne de caractères (ou d’une ligne si l’option m est active) |
$ Dollar |
Représente la fin d’une chaîne de caractères (ou d’une ligne si l’option m est active) |
| Barre verticale |
Opérateur d’alternative entre l’élément de gauche et celui de droite |
. Point |
Remplace n’importe quel caratère, hormis un saut de ligne (sauf si l’option s est active) |
* Astérisque |
Nombre d’occurence de zéro ou plus du caractère ou de la séquence de caractère qui le précède |
+ Signe plus |
Nombre d’occurence de un ou plus du caractère ou de la séquence de caractère qui le précède |
? Point d’interrogation |
Nombre d’occurence de zéro ou un du caractère ou de la séquence de caractère qui le précède |
{ } Accolades |
spécifient un intervalle de nombre d’occurences du caractère ou de la séquence de caractère qui le précède |
( ) Parenthèses |
Respectivement ouverture et fermeture d’un sous-masque ou séquence de caractères |
[ ] Crochets |
Respectivement ouverture et fermeture d’une classe de caractères |
Note : Pour utiliser dans une expression régulière un caractère spécial pour ce qu’il représente, vous devez l’échapper à l’aide d’un antislashe.
Classes de caractères
Une classe de caractères est une liste de caractères potentiels. La classe de caractère remplace uniquement un caractère dans le masque (sauf indication contraire avec en spécifiant le nombre ou l’intervalle de nombre d’occurences). Dans une classe, le signe moins (-
) devient un caractère spécial s’il n’est pas au début ou à la fin de la classe de caractère et peut alors désigner une intervalle de caractères. De plus, si vous placez un accent circonflexe au début de la classe, c’est alors une classe d’exclusion (pas ce ou ces caractère)
a[b-d]
- Désigne une chaine contenant
a
suivi deb
,c
oud
^a[b-d]{1,3}
- Désigne une chaine commençant par
a
suivi de un à trois caractères qui soientb
,c
oud
a[^0-9]+$
- Une chaîne se terminant par
a
suivi d’un ou plusieurs caractères autre qu’un chiffre
Note : On aurait pu utiliser à la place de [b-d]
la séquence (b|c|d)
, cependant, cela se révèle vite ingérable avec de grands intervalles de caractères, et, de plus, c’est moins optimal qu’une classe de caractères.
Note : Dans une classe de caractères, les caractères spéciaux (tableau précédent) perdent leur capacité spéciale hormis les caractères suivants :
Caractère | Utilité |
---|---|
\ Antislashe |
Caractère d’échappement à usage multiple |
^ Accent circonflexe |
Placé en premier dans la classe, signifie une classe d’exclusion |
] Crochet fermant |
Termine la classe de caractère |
- Signe moins |
Spécifie un intervalle de caractères sauf si placé au début ou à la fin de la classe |
Si vous désirez utiliser le crochet fermant (]
) ou le signe moins (-
) dans une classe de caractère autrement que pour leur capacité spéciale, vous devez les échapper avec un antislashe ou les placer en premier dans la classe de caractère (ou en dernier pour le signe moins).
Voici quelques autres exemples :
[.$?+*]
- Une classe contenant des caractères qui auraient une capacité spéciale en dehors de cette classe
[]a-z-]
- Un exemple de classe comprenant les caractères
]
et-
(le dernier de la classe) simplement pour ce qu’ils sont [^a-d]
- N’importe quel caractère qui n’est ni
a
, nib
, nic
, nid
Il existe en outre de nombreux intervalles de caractères prédéfinies. Les voici :
Noms de l’intervalle | Description |
---|---|
[:alnum:] |
Tout caractère alphanumérique; équivaut à a-zA-Z0-9 |
[:alpha:] |
Tout caractère alphabétique, équivaut à a-zA-Z |
[:blank:] |
Tout caractère blanc (espacement, tabulation…) |
[:digit:] |
Tout caractère numérique, équivaut à 0-9 |
[:punct:] |
Tout caractère de ponctuation |
[:space:] |
Caractère d’espacement |
[:xdigit:] |
Tout caractère héxadécimal; équivaut à a-fA-F0-9 |
[:ctrl:] |
Tout caractère de contrôle |
[:print:] |
Tout caractère imprimable (hormis les caractères de contrôle) |
Exemples concrets d’expressions régulières
Exemple n°1 : Valider un mot de passe
Pour construire un masque valide, il va nous falloir résonner de façon logique. Se poser la question : « A quoi je peux m’attendre précisément ? »
Dans le cas d’un mot de passe par exemple, nous n’allons valider que les mots contenant des caractères alphanumériques, le signe moins ou underscore (_
) et comportant au moins 4 caractères et au maximum 32 caractères.
Cela nous donnerait donc comme masque :
^[[:alnum:]_-]{4,32}$
Mise en pratique :
<?php
if( ereg('^[[:alnum:]_-]{4,32}$', $pass) )
{
echo 'Mot de passe valide';
}
else
{
echo 'Mot de passe non valide';
}
?>
Exemple n°2 : Valider une URL
Nous allons maintenant construire un masque qui nous permettra de vérifier l’adresse web d’un site.
Pour commencer, l’adresse d’un site doit commencer par http:// :
^http://
Cependant, certains sites sont sécurisés et leur adresse commence donc par https://
Intégrons cela dans notre masque :
^http(s)?://
C’est un bon début, mais on peut faire bien mieux !
Nous allons ajouter une classe de caractère pour ce qui suit //, cela peut être www mais aussi le nom d’un sous domaine. Un nom de domaine (de même qu’un sous domaine) peut être constitué de lettres, de chiffres ou du signe moins.
^http(s)?://[-[:alnum:]]+\.[-[:alnum:]]+
Ajoutons maintenant l’extension du domaine (.com, .net, etc…); elle ne peut être constituée que de lettres et de 2 à 4 caractères.
^http(s)?://[-[:alnum:]]+\.[-[:alnum:]]+\.[a-zA-Z]{2,4}
Enfin, l’adresse peut également contenir un numéro de port :
^http(s)?://[-[:alnum:]]+\.[-[:alnum:]]+\.[a-zA-Z]{2,4}(:[0-9]+)?$
Voila, nous avons maintenant un masque valide pour vérifier la validité syntaxique d’une adresse web entrée dans un formulaire (ex: inscription à un espace membre). Remarquez les caractères de point échappés avec un antislashe.
Le masque peut encore être amélioré bien sûr, par exemple, en sachant qu’un nom de domaine (sans www. ni l’extension) ne peut faire que 63 caractères maximum, ou encore qu’un nom de domaine ne peut ni commencer, ni finir par un tiret.
Mise en pratique :
<?php
$string = 'https://www.phpcodeur.net';
if( ereg('^http(s)?://[-[:alnum:]]+\.[-[:alnum:]]+\.[a-zA-Z]{2,4}(:[0-9]+)?$', $string) )
{
echo 'Adresse web valide';
}
else
{
echo 'Adresse web non valide';
}
?>
Conclusion
Nous avons donc eu un aperçu des puissantes possibilités des expressions régulières. Elles peuvent être utiles en maintes occasions, et parfois, être indispensables. Si on ajoute à cela que les expressions sont utilisées de façon universelles, apprendre leur mécanisme constitue presque un passage obligé.
Nous verrons dans la prochaine partie les différentes fonctions php utilisant les regex. Et nous aborderons également le principe des sous-masques capturants, l’utilisation des caractères ‘invisibles’, les différents options de recherche disponibles, ainsi que les références arrières qui peuvent s’avérer très pratique dans certains cas.
Enfin, dans la troisième partie, nous tenterons de prendre le taureau par les cornes en nous attaquant aux assertions, aux sous-masques uniques ou conditionnels, la possibilité de placer des commentaires au sein des masques complexes, et enfin les masques récursifs.
Liens connexes
- Manuel php : Syntaxe des masques
- [1] : Le mot Regexp est une contraction de Regular expressions, on utilise aussi parfois le mot Regex
- [2] : Lorsque l’on veut appliquer des directives de redirection avec
RedirectMatch
par exemple, ou encore en utilisant le mod_rewrite et la réécriture d’URL - [3] : De façon tout à fait minime avec les sélecteurs de type
a[hreflang|="en"]
, mais d’autres choses tout à fait passionnantes nous attendent avec les CSS de niveau 3 🙂
1 Comment