Construire une regex complète



Vous allez enfin comprendre pourquoi vous en avez bavé tout le long !
Cette fois, nous allons toucher du concret à travers des exemples qui vous seront sûrement utiles. Nous allons construire de grosses regex ensemble, pour que vous compreniez la méthode. Ensuite, vous serez tout à fait capables d'inventer vos regex et de vous en servir pour vos scripts PHP !


Un numéro de téléphone


Pour cette première vraie regex, nous allons essayer de voir si une variable (entrée par un visiteur via un formulaire, par exemple) correspond bien à un numéro de téléphone.


Je vais me baser sur les numéros de téléphone français, il faudra donc m'excuser si vous n'êtes pas français et que vous ne connaissez pas. L'avantage, c'est que vous pourrez ensuite vous exercer à écrire cette regex pour les numéros de téléphone de votre pays.


Pour rappel (et pour ceux qui ne savent pas, donc), un numéro de téléphone français comporte 10 chiffres. Par exemple : « 01 53 78 99 99 ». Il faut respecter les règles suivantes :

  • le premier chiffre est TOUJOURS un 0 ;
  • le second chiffre va de 1 à 6 (1 pour la région parisienne… 6 pour les téléphones portables), mais il y a aussi le 8 (ce sont des numéros spéciaux). À noter que le 7 et le 9 commencent à être utilisés mais que nous ne les prendrons pas en compte dans nos exemples ;
  • ensuite viennent les 8 chiffres restants (ils peuvent aller de 0 à 9 sans problème).

Pour commencer, et pour faire simple, on va supposer que l'utilisateur entre le numéro de téléphone sans mettre d'espace ni quoi que ce soit (mais on complique juste après, et vous verrez que c'est là le véritable intérêt des regex).


Ainsi, le numéro de téléphone doit ressembler à ça : « 0153789999 ». Comment écrire une regex qui corresponde à un numéro de téléphone comme celui-ci ?

Voici comment je procède, dans l'ordre, pour construire cette regex.

  1. Primo, on veut qu'il y ait UNIQUEMENT le numéro de téléphone. On va donc commencer par mettre les symboles ^ et $ pour indiquer un début et une fin de chaîne :

#^$#

  1. Continuons. On sait que le premier caractère est forcément un 0. On tape donc :

#^0$#

  1. Le 0 est suivi d'un nombre allant de 1 à 6, sans oublier le 8 pour les numéros spéciaux. Il faut donc utiliser la classe [1-68], qui signifie « Un nombre de 1 à 6 OU le 8 » :

#^0[1-68]$#

  1. Ensuite, viennent les 8 chiffres restants, pouvant aller de 0 à 9. Il nous suffit donc d'écrire [0-9]{8}pour indiquer que l'on veut 8 chiffres. Au final, ça nous donne cette regex :

#^0[1-68][0-9]{8}$#


Et c'est tout !


Bon, je vois que vous êtes en forme, alors ne nous arrêtons pas en si bon chemin et améliorons cette regex. 
Maintenant, on va supposer que la personne peut taper un espace tous les deux chiffres (comme c'est courant de le faire en France), mais aussi un point ou un tiret. Notre regex devra donc accepter les numéros de téléphone suivants :

  • 0153789999
  • 01 53 78 99 99
  • 01-53-78-99-99
  • 01.53.78.99.99
  • 0153 78 99 99
  • 0153.78 99-99
  • etc.


Et c'est là qu'est toute la puissance des regex !
Les possibilités sont très nombreuses, et pourtant vous avez juste besoin d'écrire la regex correspondante.


On reprend donc la création de notre regex.

  1. Primo, le 0 puis le chiffre de 1 à 6 sans oublier le 8. Ça, ça ne change pas :

#^0[1-68]$#

  1. Après ces deux premiers chiffres, il peut y avoir soit un espace, soit un tiret, soit un point, soit rien du tout (si les chiffres sont attachés). On va donc utiliser la classe [-. ] (tiret, point, espace).

Mais comment faire pour dire que le point (ou le tiret, ou l'espace) n'est pas obligatoire ? Avec le point d'interrogation, bien sûr ! Ça nous donne : #^0[1-68][-. ]?$#

  1. Après le premier tiret (ou point, ou espace, ou rien), on a les deux chiffres suivants. On doit donc rajouter [0-9]{2} à notre regex.

#^0[1-68][-. ]?[0-9]{2}$#

  1. Et maintenant, réfléchissez. Il y a moyen de terminer rapidement : on a juste besoin de dire que « [-. ]?[0-9]{2} » doit être répété quatre fois, et notre regex est terminée ! On va se servir des parenthèses pour entourer le tout, et placer un {4} juste après pour indiquer que tout ça doit se répéter quatre fois. Ce qui nous donne finalement :

#^0[1-68]([-. ]?[0-9]{2}){4}$#

Vous pouvez l'encadrer en gros en poster dans votre chambre : c'est votre première VRAIE regex !

#^0[1-68]([-. ]?[0-9]{2}){4}$#

Voici un petit script que j'ai fait rapidement, pour que vous puissiez tester toute la puissance des regex :

<p>

<?php

if (isset($_POST['telephone']))

{

    $_POST['telephone'] = htmlspecialchars($_POST['telephone']); // On rend inoffensives les balises HTML que le visiteur a pu entrer

 

    if (preg_match("#^0[1-68]([-. ]?[0-9]{2}){4}$#", $_POST['telephone']))

    {

        echo 'Le ' . $_POST['telephone'] . ' est un numéro <strong>valide</strong> !';

    }

    else

    {

        echo 'Le ' . $_POST['telephone'] . ' n\'est pas valide, recommencez !';

    }

}

?>

</p>

 

<form method="post">

<p>

    <label for="telephone">Votre téléphone ?</label> <input id="telephone" name="telephone" /><br />

    <input type="submit" value="Vérifier le numéro" />

</p>

</form>

Vous pouvez essayer tous les numéros de téléphone que vous voulez, avec des espaces au milieu ou non si ça vous chante : la regex gère tous les cas.


Vous auriez pu aussi utiliser le raccourci \d pour indiquer un chiffre dans votre regex :
#^0[1-68]([-. ]?\d{2}){4}$#
Personnellement, je trouve que mettre [0-9] est quand même plus clair.


Une adresse e-mail


Ça serait dommage de s'arrêter sur une si bonne lancée.
Je vais donc vous présenter un deuxième exemple qui vous sera certainement utile : tester si l'adresse e-mail est valide.


Alors, avant de commencer quoi que ce soit, et pour qu'on soit bien d'accord, je vais rappeler comment est construite une adresse e-mail.

  1. On a tout d'abord le pseudonyme (au minimum une lettre, mais c'est plutôt rare). Il peut y avoir des lettres minuscules (pas de majuscules), des chiffres, des points, des tirets et des underscores « _ ».
  2. Il y a ensuite une arobase : @.
  3. Ensuite il y a le nom de domaine. Pour ce nom, même règle que pour le pseudonyme : que des minuscles, des chiffres, des tirets, des points et des underscores. La seule différence – vous ne pouviez pas forcément deviner – c'est qu'il y a au moins deux caractères (par exemple, « a.com » n'existe pas, mais « aa.com » oui).
  4. Enfin, il y a l'extension (comme « .fr »). Cette extension comporte un point, suivi de deux à quatre lettres (minuscules). En effet, il y a « .es », « .de », mais aussi « .com », « .net », « .org », « .info », etc.


L'adresse e-mail peut donc ressembler à j.dupont_2@orange.fr.


Construisons la regex.

  1. Primo, comme tout à l'heure, on ne veut QUE l'adresse e-mail ; on va donc demander à ce que ça soit un début et une fin de chaîne :

#^$#

  1. Ensuite, on a des lettres, chiffres, tirets, points, underscores, au moins une fois. On utilise donc la classe[a-z0-9._-] à la suite de laquelle on rajoute le signe + pour demander à ce qu'il y en ait au moins un :

#^[a-z0-9._-]+$#

  1. Vient ensuite l'arobase (là ce n'est pas compliqué, on a juste à taper le caractère) :

#^[a-z0-9._-]+@$#

  1. Puis encore une suite de lettres, chiffres, points, tirets, au moins deux fois. On tape donc {2,} pour dire « deux fois ou plus » :

#^[a-z0-9._-]+@[a-z0-9._-]{2,}$#

  1. Ensuite vient le point (de « .fr » par exemple). Comme je vous l'ai dit plus haut, c'est un caractère spécial qui sert à indiquer « n'importe quel caractère » (même des accents). Or, ici, on veut enlever sa signification au point pour dire que l'on veut le symbole point dans notre regex. On va donc mettre un antislash devant :

#^[a-z0-9._-]+@[a-z0-9._-]{2,}\.$#

  1. Enfin, pour terminer, il nous faut deux à quatre lettres. Ce sont forcément des lettres minuscules, et cette fois pas de chiffre ou de tiret, etc. On écrit donc :

#^[a-z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,4}$#

Et voilà encore une nouvelle regex de bouclée !

#^[a-z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,4}$#

Vous sentez que vous commencez à parler chinois, non ? ;-)

Allez, je suis en forme et de bonne humeur, je vous donne le script PHP pour tester cette regex :

<p>

<?php

if (isset($_POST['mail']))

{

    $_POST['mail'] = htmlspecialchars($_POST['mail']); // On rend inoffensives les balises HTML que le visiteur a pu rentrer

 

    if (preg_match("#^[a-z0-9._-]+@[a-z0-9._-]{2,}\.[a-z]{2,4}$#", $_POST['mail']))

    {

        echo 'L\'adresse ' . $_POST['mail'] . ' est <strong>valide</strong> !';

    }

    else

    {

        echo 'L\'adresse ' . $_POST['mail'] . ' n\'est pas valide, recommencez !';

    }

}

?>

</p>

 

<form method="post">

<p>

    <label for="mail">Votre mail ?</label> <input id="mail" name="mail" /><br /> 

    <input type="submit" value="Vérifier le mail" />

</p>

</form>


Testez donc des adresses comme :

  • the_cypher@hotmail.com ;
  • business_consultants@free4work.info ;
  • mega-killer.le-retour@super-site.fr.st ;
  • etc., etc.


Alors, ça vous plaît ?


Je reconnais que ça paraît être très complexe quand on lit une regex la première fois. J'imagine la tête que vous avez dû faire lorsque je vous en ai montré une dans l'introduction du chapitre précédent. ;-)

Mais bon, vous voyez le progrès ? On vient ensemble d'écrire un de ces fameux trucs imbuvables, et je ne pense pas que beaucoup d'entre vous pensaient y arriver en lisant le chapitre précédent !
Pourtant nous y voilà : nous avons réussi à écrire deux regex complètes. Je ne vais pas vous faire travailler sur une troisième, vous avez – je pense – compris le principe et vous savez vous débrouiller comme des grands.

Je veux juste vous montrer une dernière petite chose avant de passer à la dernière notion importante que nous aborderons (capture et remplacement).


Des regex… avec MySQL !


Comme quoi, vous allez vraiment être heureux d'en avoir un peu bavé pour arriver jusqu'ici.
Eh oui, grrrande nouvelle : MySQL comprend les regex !


Et ça, bah c'est tout bénef' pour vous : vous venez d'apprendre à écrire des regex, vous n'avez presque rien à savoir de plus pour vous en servir avec MySQL.


Il faut savoir cependant que MySQL ne comprend que les regex en langage POSIX, et pas PCRE comme on a appris.

Vous avez juste besoin de retenir ce qui suit pour faire une regex POSIX :

  • il n'y a pas de délimiteur ni d'options. Votre regex n'est donc pas entourée de dièses ;
  • il n'y a pas de classes abrégées comme on l'a vu plus haut, donc pas de \d, etc. En revanche, vous pouvez toujours utiliser le point pour dire : « n'importe quel caractère ».


Le mieux, bien entendu, c'est toujours un bon exemple. Supposons que vous ayez stocké les IP de vos visiteurs dans une table visiteurs et que vous vouliez les noms des visiteurs dont l'IP commence par « 84.254 » :

SELECT nom FROM visiteurs WHERE ip REGEXP '^84\.254(\.[0-9]{1,3}){2}$'


Cela signifie : Sélectionne tous les noms de la table visiteurs dont l'IP commence par « 84.254 » et se termine par deux autres nombres de un à trois chiffre(s) (ex. : 84.254.6.177).


Toute la puissance des regex dans une requête MySQL pour faire une recherche très précise… Ça ne se refuse pas. ;-)
Je ne m'étends pas plus là-dessus, je sais que vous saurez vous débrouiller si jamais cela vous est utile.

Passons maintenant à la dernière notion importante avec les regex : « capture et remplacement » !

Créé avec HelpNDoc Personal Edition: Repérez et corrigez sans effort les problèmes dans votre documentation avec l'analyseur de projet de HelpNDoc