Les expressions régulières: Première partie

 

Les expressions régulières: Première partie

  1. Introduction aux expressions régulières
  2. Syntaxe de base
  3. Classes de caractères
  4. Exemple n°1 : Valider un mot de passe
  5. Exemple n°2 : Valider une URL
  6. Conclusion
  7. Liens connexes

Introduction aux expressions régulières

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 encore aa
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 plusieurs b
ab+
Un a suivi de un ou plusieurs b
ab?
Un a suivi 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.?
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è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
Acceptera les mots bonjour ou soir
bon(jour|soir)
Acceptera les mots bonjour ou bonsoir
php is (cool|funny)
Acceptera la chaîne php is cool ou la chaîne php is funny
mouarf (arf ){0,2}
Acceptera la chaîne mouarf, mouarf arf ou mouarf arf arf

Voici un tableau des différents caractères spéciaux et leur utilité :

Tableau des caractères spéciaux
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 de b, c ou d
^a[b-d]{1,3}
Désigne une chaine commençant par a suivi de un à trois caractères qui soient b, c ou d
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 :

Tableau des caractères spéciaux dans une classe
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, ni b, ni c, ni d

Il existe en outre de nombreux intervalles de caractères prédéfinies. Les voici :

Tableau des intervalles de caractères prédéfinies
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)

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 = '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';
}

?>

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

Article écrit le / Mis à jour le par Bobe
[18] commentairesTop

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 [lien]?var1=truc&var2=truc2
ou meme avec l'url de cette page
ht [lien]
(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.

Auteur : Antoine • 29/03/2009 @ 00:18 • #112204

Bonjour,
article très bien fait, malheureusement les intervalles prédéfinis ne marchent pas chez moi
enfin ce n'est pas très grave, par contre les expressions :
[-[a-z]]
ne marchent pas,
seul :
[a-z-] marche
donc si vous avez un problème sur des expression simple pour des url par ex., ca peut être à cause de ca.

Déposer un commentaire

Pseudo, Email et Options

Tapez votre commentaire

Note : Vos données personnelles restent strictement confidentielles et ne sont pas réutilisées à votre insu. Vous pouvez consulter à ce propos cette page.

Valid HTML Valid CSS Mozilla et Firebird ipv6 ready