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.
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 blob
gulp$ gulp
^texte$ texte
texte 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} aaa
a{0,2} a, ou encore
aa
a{1,} 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* asuivi de zéro ou plusieurs
b
ab+ asuivi de un ou plusieurs
b
ab? asuivi de zéro ou un
b
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.? asuivi de zéro ou un caractère quelconque
^.{3}a a
a|b aOU le caractère
b
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 bonjourou
soir
bon(jour|soir) bonjourou
bonsoir
php is (cool|funny) php is cool ou la chaîne php is funny mouarf (arf ){0,2} mouarf,
mouarf arfou
mouarf 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.
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] asuivi de
b,
cou
d
^a[b-d]{1,3} asuivi de un à trois caractères qui soient
b,
cou
d
a[^0-9]+$ asuivi 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 :
[.$?+*] []a-z-] ] et - (le dernier de la classe) simplement pour ce qu'ils sont [^a-d] a, ni
b, ni
c, ni
d
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) |
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';
}
?>
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 = 'http://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';
}
?>
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.
RedirectMatch par exemple, ou encore en utilisant le mod_rewrite et
la réécriture d'url a[hreflang|="en"],
mais d'autres choses tout à fait passionnantes nous attendent avec les
css de niveau 3 :) Note : Vos données personnelles restent strictement confidentielles et ne sont pas réutilisées à votre insu. Vous pouvez consulter à ce propos cette page.
Des commentaires ?
Auteur : Iceman • 12/02/2003 @ 12:46 • #203
excellent il nous manquait un peu d'info sur le regex.
Humm sans vouloir être prétentieux bobe ton site commence à ressembler à phpinfo.net. Enfin pour moi il devient incontournable.
Auteur : Francky • 21/02/2003 @ 07:54 • #216
grâce à tes lumières, j'ai pu écrire en une instruction l'équivalent de 40 lignes de code. Merci (c'est puissant)
Auteur : Daniel JACKSON • 21/04/2003 @ 14:58 • #292
Alors là, c'est... comment dire... enfin bref, y'a pas d'mot ! :-) :-) :-)
Auteur : kam • 23/04/2004 @ 11:34 • #545
salut
je voudrais savoir si vous pouvez m'aider à trouver une class qui traite des expressions régulières en c++
@++
Auteur : noiz • 10/05/2004 @ 23:21 • #557
terrible ce tuto.
c'est bcp plus clair pour moi les regexp maintenant
en plus les filles se jéent à mes pieds et mes cheveux ont repoussé.
milles merci
Auteur : FReD • 05/06/2004 @ 14:20 • #578
Très bon article mais c'est dommage de se mimiter aux ereg alors que les compatibles perl (PREG) sont encore beaucoup plus puissantes, et pas beaucoup plus compliquées...
Auteur : Bobe • 09/06/2004 @ 16:35 • #582
FReD: En fait, cet article n'est qu'une introduction aux expressions régulières, d'où le fait que je me sois contenté de ereg().
Deux autre articles devaient suivre (voir le chapitre "conclusion"), mais je ne les ai toujours pas pondu.
Auteur : Zipjo • 26/06/2004 @ 21:06 • #594
'Pourvu que ça dure'
Franchement super, je cherchais a les comprendre et les ait enfin comprit ^^
Merci!
Auteur : BestFF • 29/07/2004 @ 18:01 • #601
Vraiment génial, expliqué de façon très claire, merci beaucoup !
Auteur : FeelTheWay • 03/02/2005 @ 15:50 • #653
Merci tout simplement :)
Auteur : nemesis • 24/06/2005 @ 02:40 • #698
pas mal le tuto sauf au niveau de la regex de l'url qui si donnera false avec un url et des variables de cette forum:
ht [Cliquez ici]?var1=truc&var2=truc2
ou meme avec l'url de cette page
ht [Cliquez ici]
(bien sure sans espace entre ht et tp
Auteur : Bobe • 25/06/2005 @ 23:20 • #699
Oui. En fait, l'exemple concerne plutôt la validation de l'adresse d'un site (comprendre: adresse de la page d'accueil). Le titre du paragraphe peut induire en erreur.
Mais j'avais fait ce paragraphe surtout pour le coté didactique. Car en utilisation réel, il faudrait tenir compte des adresses sans indication de sous-domaine ainsi que de la présence éventuelle d'un slashe après l'extension ou le numéro de port, etc.
Auteur : lagzor • 04/06/2006 @ 15:32 • #989
SUPER !!!
Je cherchais depuis longtemps comment faire en sorte que ma variable contienne que des lettres, grace à ce site j'ai trouvé !
Merci
Pour ceux qui n'ont toujours pas trouvé :
if( ereg('^[[:digit:]]{1,10}$', $variable) ) {
Que des chiffres qui contienne de 1 a 10 caractères !
MERCI CE SITE EST GENIAL !
Auteur : YoupLABoum • 02/11/2006 @ 10:31 • #2434
Pas mais il manque le cas ou l'adresse est h t t p: // domaine . com
La le script me dit domaine invalide alors que c'est faux !!
Je propose ca :
if( ereg('^http(s)?://([-[:alnum:]]+)?(\.)?[-[:alnum:]]+\.[a-zA-Z]{2,4}(:[0-9]+)?$', $string) )
Auteur : bobe • 07/12/2006 @ 02:47 • #2639
Bonne remarque :-)
Cela dit, il faut voir cet exemple pour son coté simple à comprendre.
Auteur : d00.css • 31/01/2007 @ 00:23 • #3027
Je découvre ce site et je réalise ô combien il est bien agencé et ô combien son contenu est riche et rédigé avec soin.
Je suis impressionné et je le grâve à tout jamais dans ma ROM
^ Bobe !
Auteur : divin • 09/03/2007 @ 15:49 • #3364
dieu te garde mon fils. maintenant tu es prêt à affronter tes démons.
continue ainsi et tu verras la lumière.
que l'expression régulière soit avec toi.