Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Les expressions régulières compatibles PERL en PHP, partie 1

Compatible PHP. Cliquer pour en savoir plus sur les compatibilités.Par qwix, le 25 mai 2005

Introduction

Dans ce tutorial, vous trouverez une description des expressions régulières(ou rationelles) compatibles PERL, ou plus communement appelées PCRE: Perl Compatible Regular Expressions. Ce tutorial est un condensé de ce qui est le plus important à savoir à propos des expressions régulières il n'est malheureusement pas complet car traiter un tel sujet ne se limite pas à un tutorial, il faudrait un livre entier pour apprécier la puissance et l'art de composer une expression régulière correspondant à ses besoins. J'espère simplement que ce tutorial vous sera utile, et si jamais vous avez des critiques, des suggestions ou autres à me faire parvenir, n'hésitez pas à me le faire savoir sur cette adresse email: qwix@dreamweaver-forum.net .

Qu'est ce qu'une expression régulière?

Les expressions régulières sont une suite d'expressions logiques qui permettent de vérifier le format d'une chaine de caractères devant correspondre à un modèle précis. Issues du monde UNIX, celles-ci ont été très largement utilisées et répandues dans PERL, qui est devenu un des langages de référence pour l'utilisation des expressions régulières. Elles permettent de traiter les chaines d'une façon si puissante qu'il serait très difficile voire impossible de faire la même chose en utilisant simplement les fonctions de chaines standards.

Structure d'une expression régulière

Une expression régulière est composée de deux parties:

  1. la première est constitutée par le modèle qui sera appliqué à la chaine de caractère
  2. la seconde correspond aux options possibles que l'on peut coupler au modèle.

Pour différencier la première de la seconde partie, on utilise des séparateurs prédéfinis qui sont soit le slash ‘/’ soit le dièse ‘#’. qui est un caractère que l'on choisit. Ainsi on peut écrire une expression régulière comme ceci:

$regex = "#le_modèle#options_possibles"; // Ici le séparateur est #

ou encore

$regex = "/le_modèle/options_possibles";// Ici le séparateur est /

Pour ma part je préfère la première notation car elle permet de bien différencier le modèle et les options, la lisibilité d'une expressions régulière étant très importante pour la compréhension et la maintenance, surtout en cas de modèles complexes. Dans tout les cas vous pouvez choisir l’un ou l’autre comme bon vous semble, L'essentiel est que vous soyez capables de vous relire par la suite ;)

Les métas caractères

l'antislash(ou backslash): \caractère

L'antislash '\' permet d'échapper des caractères dit spéciaux, c'est à dire des caractères qui ont un sens dans le langage des expressions régulières, il permet de dire au moteur qui traite le modèle que le caractère suivit de '\' a une signification spéciale et qu'il ne faut pas le traiter comme un simple caractère. L'antislash permet aussi d'échapper les slashes '/' qui déterminent la fin du modèle et le début des options de l'expression. En effet un peu plus haut j'ai dit qu'il était possible d'écrire une expression régulière de cette façon:

$regex = \"/le_modèle/options_possibles\" ;

Si jamais le modèle doit contenir un slash, celui-ci doit être échappé avec antislash '\', sinon il risquerait de terminer trop tôt le modèle et vous obtiendriez des erreurs de compilations de votre expression ;-) . Autrement dit, si vous devez utilisez un '/', que vous utilisez cette notation $regex = ”/le_modèle/options_possibles” ; et que ce '/' n'est pas censé terminer votre modèle, échappez le toujours avec un '\' devant.

Certaines combinaisons d'un caractère avec '\' signifie quelque chose de bien particulier dans le langage des expressions régulières, vous trouverez la liste de ceux utilisables pas les PCRE de PHP.

liste des métas caractères d'abréviation

Cette liste de métacaractères permet d'avoir une représentation visuelle un peu plus claire pour certains caractères contenus dans les chaines de caractères. Par exemple seriez-vous capables de reconnaitre la différence entre une tabulation et plusieurs espaces si vous deviez les saisirs tels quels ? A moins d'être équipé d'une vision bionique je voit mal comment ce serait possible, cette liste est faite pour vous aider à en reconnaitre une bonne partie et ce, sans subir de fatigue visuelle importante, même si je vous l'accorde, noyé dans un modèle un peu complexe on se perd facilement.

  • \b: Backspace Dans les classes de caractères, c'est l'espace inverse, sinon c'est une limite de mot.
  • \e: Escape character C'est le caractère d'échappement.
  • \f: Form feed C'est une nouvelle page.
  • \n: Newline C'est le caractère de nouvelle ligne.
  • \r: Carriage retour C'est le caractère de retour chariot.
  • \t: Normal tab C'est la tabulation.

Vous avez aussi la possibilité de reconnaitre des caractères dont vous connaissez le code hexadécimal. Il suffit de faire suivre l'antislash du caractère x suivi du code hexadécimal du caractère à rechercher. Pour le code octal, il suffit de le faire précéder d'un zéro.

Voici donc, si cela peut vous aider l'équivalence ASCII et octale des métacaractères présentés ci-dessus:

  • \b: ASCII: <BS> octal: 010
  • \e: ASCII: <ESC> octal: 033
  • \f: ASCII: <FF> octal: 014
  • \n: ASCII: Unix, Dos et Windows: <LF>, MacOS: <CR> octal: Unix, Dos et Windows: 012, MacOS: 015
  • \r: ASCII: <CR>, MacOS:<LF> octal: 015
  • \t: ASCII: <HT> octal: 011

Les classes de caratères spéciales

Les classes de caractères permet de décrire de façon lisible un groupe de caractère spécifiques, en voici la liste:

Liste des classes de caractères spécifiques

  • \d: Chiffre Reconnait tout caractère décimal.
  • \D: Non chiffre Reconnait tout ce qui n'est pas décimal. Généralement équivalent à [^\d].
  • \w: Caractère constituant un mot Reconnait tout caractère alphanumérique ainsi que le tiret bas '_'. Généralement équivalent à [a-zA-Z0-9_], cependant il existe une subtilité avec les caractères accentués dont nous reparlerons plus tard.
  • \W: Caractère non constituants d'un mot Reconnait tout caractère non alphanumérique ni le tiret bas '_'. Généralement équivalent à [^\w].
  • \s: Caractère d'espacement Reconnait tout caractère blanc. Equivalent trop peu lisible.
  • \S: Caractère de non espacement Reconnait tout ce qui n'est pas un caractère blanc. Généralement équivalent à [^\s].

Les crochets: [ ]

Les caractères contenus entre des crochets représentent une classe de caractères, c'est à dire une liste de caractères autorisés que l'on peut trouver dans la chaine cible. La classe de caractères représente, un seul et caractère parmi tous ceux qui sont autorisés dans la classe. Elle permet donc de reconnaitre un caractère parmis une liste de plusieurs possibles.

Prenons une phrase d'exemple:

  J'utilise une souris Microsoft

Mais que par erreur je me trompe en tappant Microsoft et que je tape Mikrosoft (Non ce n'est pas le K d'une célèbre marque de bière bon marché :mrgreen: ). Comment faire pour retrouver quand même ce mot ? Il suffit de créer une classe de caractère qui autorise le 'c' et le 'k'.

Ainsi je pourrais créer le modèle suivant:

$regex = "#Mi[ckCK]rosoft#";

Ainsi je peux taper ce mot comme je le souhaite c'est à dire: Microsoft ou Mikrosoft ou MiCrosoft ou MiKrosoft puisque que j'ai autorisé les caractères 'c', 'k', 'C' et 'K' j'ai donc traité la possiblité d'avoir les lettres en majuscules. Nous verrons plus tard qu'il est possible d'utiliser une option d'insensibilité à la casse, ce qui nous évite de nous préoccuper des différences entre majuscules et minuscules.

Une méthode efficace pour comprendre -et par la suite rédiger- un modèle d'expression régulière, est de le lire à haute voix. Pour cet exemple on aurait:

  "Je cherche un mot qui commence par M puis i, suivi de soit c, soit k, soit C, soit K, puis r, puis o, puis s, puis o, puis f, puis t".

Ainsi le fait de le dire à haute voix vous fait comprendre les choses plus rapidement ;-)

Voici par exemple quelques classes de caractères très utiles, mais par contre pas très lisible si elles ne sont pas utilisées avec parcimonie: 1: [-a-zA-Z0-9_] Accepte tout caractères alphanumérique, ainsi que le tiret et le tiret bas, sans ce soucier de la casse du caractère. 2: [0-9] Accepte tout caractère numérique.

Dans la partie pratique, nous verrons comment traiter efficacement les nombres avec ces classes de caractères.

Remarque Lorsque que vous souhaitez utiliser des classes de caractère sur des caractères accentués comme 'é', 'è'…. la classe [a-zA-Z0-9-_] ne fonctionnera pas, en effet celle-ci ne gère pas les caractères accentués des chaines de caractères, vous pouvez bien sur rajouter le ou les caractères accentués dans la classe mais vous obtiendrez vite un charabia incompréhensible et illisible, surtout si vous voulez gérer la totalité des accents. Vous pourriez par exemple obtenir ceci: [éèàöôa-zA-Z0-9] bien sur je n'ai pas mis la totalité des caractères accentués, comme vous pouvez le voir ce n'est pas lisible du tout. L'astuce consiste donc à utiliser la classe \w qui elle gère les caractères accentués ;-).

Les parenthèses: ( )

Elles délimitent un sous-motif et peuvent contenir d'autres expressions régulières. Le texte qui est reconnu par le motif entre elles sera capturé et stocké en mémoire, pour être utilisés plus tard grâce aux références arrières dont nous reparlerons un peu plus loin.

Contrairement aux crochets, les parenthèses permettent de stocker une séquence ou une suite figée de caractères, c'est à dire que les caractères doivent apparaitre dans le même ordre que celui cité dans les parenthèses.

Prenons un exemple:

  Chacun cherche son chat.

Je souhaite récupérer le mot 'chat'. Je pourrais me dire “ok chat est composé d'un 'c' d'un 'h' d'un 'a' et d'un 't', je peux donc utiliser la classe de caractères [chat]{4}” ne vous préoccupez pas de '{4}' nous verrons sa signification un peu plus loin ;-) Quel est le résultat obtenu lorsque que l'on applique ce modèle à notre phrase ? On obtient effectivement le mot 'chat', maintenant mélangeons les lettres de ce mot et remplaçons 'chat' par 'hact'. Avec le même modèle nous obtenons le résultat 'hact'. Pourquoi ? Parce que la classe de caractère est une liste de caractères autorisés et ce dans n'importe quel ordre.

Maintenant utilisons les parenthèses avec ce modèle (chat). Avec le mot 'hact' nous n'obtenons rien, par contre avec le mot 'chat' nous avons un résultat.

Pour bien comprendre l'utilité des parenthèses il ne faut pas vous dire, “je cherche le mot chat” mais plutôt, “je cherche la séquence de caractères suivante: 'c' suivi immédiatement de 'h' suivi immédiatement de 'a' suivi immédiatement de 't' ”. Vous comprendrez plus vite ;-)

Pour tester par vous même voici le script utilisé:

<?php
$chaine = array("chat", "hact", "chat", "hact") ;
$pattern = array("#[chat]{4}#", "#[chat]{4}#", "#(chat)#", "#(chat)#");
for($i=0; $i<sizeof($chaine); $i++)
{
  if(preg_match($pattern[$i], "Chacun cherche son ".$chaine[$i], $matches))
  {
    echo "une correspondance à eu lieu sur la chaine ".$chaine[$i]." et pour le modèle ".$pattern[$i]."<br/>\n" ;
    echo "<pre>" ; print_r($matches[0]) ;
    echo "</pre>" ;
  }//fin if
  else
  echo "aucune correspondance trouvée sur la chaine ".$chaine[$i]." et pour le modèle ".$pattern[$i]."<br/>\n" ;
}//fin for
?>

L'accent circonflexe: ^

Il indique le début d'une ligne de texte. Attention ce que je viens de dire est important, l'accent circonflexe indique un début de ligne et non le début d'un mot!! Autrement dit “^chien” se traduit par “Une ligne qui commence par la lettre c, suivie de h….” et pas “une chaine qui commence par chien” ce qui-à mon sens en tout cas- ne veut rien dire.

Utilisé dans une classe de caractères, l'accent circonflexe signifie une négation, par exemple [^0-9] signifie qu'on ne souhaite pas reconnaitre de caractère alphanumérique.

Le dollar: $

C'est le contraire de l'accent circonflexe, il indique une fin de ligne.

Le barre: |

Elle permet de définir une alternative c'est une traduction du mot ou. Un peu comme dans l'expression “thé ou café” la barre fonctionne exactement de la même manière. Par exemple “thé|café|chocolat” peut se traduire oralement par “thé, ou café, ou chocolat”.

Le point: .

Le point permet de reconnaitre n'importe quel caractère, mais attention son comportement peut-être vicieux si vous l'utilisez mal.

Les quantificateurs avides

Ces métas caractères permettent, comme leur nom l'indique, de définir un nombre (minimum, maximum, ou les deux simultanément) de reconnaissances pour une classe ou un masque. On les qualifie d' avides car ils ne se contentent pas d'un minimum de reconnaissances dans la chaine cible, mais d'un maximum.

Les accolades:{ }

Elles permettent de définir une plage de reconnaissances, c'est à dire un minimum et un maximum. Elles s'utilisent comme ceci: {min, max} qui permet de définir un nombre minimum et maximum de reconnaissance sur la chaine cible. {nombre} qui permet de définir un nombre exact de reconnaissances sur la chaine cible. {min, } qui permet de définir un nombre minimum de reconnaissance sur la chaine cible.

Le point d'interrogation ?

Il permet de définir une possibilité, c'est à dire qu'une reconnaissance peut avoir lieu au maximum une fois, ou ne pas avoir lieu. C'est l'équivalent plus lisible de {0,1}.

L'étoile *

Elle permet de définir aussi une possibilité étendue, c'est à dire que si la reconnaissance à lieu, il n'y a pas de maximum, par contre il est possible qu'il n'y ait aucune reconnaissance dans la chaine cible. Couplée au méta caractère point '.' c'est un couple efficace mais à utiliser avec attention. C'est l'équivalent plus lisible de {0,}.

Le plus +

Il permet de définir une obligation, c'est à dire que la reconnaissance doit avoir lieu une fois au minimum, et sans limite maximum. C'est l'équivalent plus lisible de {1,}.

La gourmandise est un vilain défaut: Pour obtenir une reconnaissance efficace il est souvent obligatoire d'utiliser un ou plusieurs quantificateurs (+, *, ? , {min, max}) le problème c'est qu'il faut faire attention lorsque l'on les utilise. En effet, ceux-ci sont très 'gourmands' c'est à dire qu'ils vont essayer d'obtenir le plus de reconnaissances possibles, il faut donc faire attention à la combinaison de ces quantificateurs.

Voyons un exemple. Prenons cette phrase:

  J'espère que l'année 2004 sera bonne pour vous.

Et utilisont cette expression régulière

#(.*)([0-9]+)(.*)#

Pour ceux qui connaissent déjà les expressions régulières, ils verront que ce pattern est complètement stupide, mais celui-ci explique bien la 'gourmandise' des quantificateurs. En effet si on teste ce pattern avec ce script:

<?php
$chaine = "J'espère que l'année 2004 sera bonne pour vous." ;
$regex = "#(.*)([0-9]+)(.*)#" ;
 
if(preg_match($regex, $chaine, $matches))
{
  echo "<pre>" ;
  print_r($matches) ;
  echo "</pre>" ;
}//fin if
?>

On obtient:

  Array
  (
     [0] => J'espère que l'année 2004 sera bonne pour vous.
     [1] => J'espère que l'année 200
     [2] => 4
     [3] =>  sera bonne pour vous.
  )

La case 0 est un ensemble de toutes les reconnaissance, ne la prenons pas en compte, par contre on voit bien que la case 2 du tableau, c'est à dire la seconde reconnaissance du modèle n'a qu'un seul chiffre, le 4 hors si jamais on ne prends que ce pattern ([0-9]+) on devrait obtenir 2004. Ceci explique bien ce que j'essaie de vous montrer, la partie (.*) prends un maximum de caractères et comme cette partie ([0-9]+) ne se contente d'un caractère numérique elle ne récupère que le 4 vu que la partie d'avant prends tout le reste précédant ce chiffre et que la partie d'après n'est pas constituée de chiffres.

J'espère qu'avec cette démonstration, vous comprenez maintenant qu'il faut faire attention avec certains quantificateurs.

Quantificateur paresseux

A l'inverse des quantificateurs avides cité ci-dessus, il existe des quantificateur dits 'paresseux', c'est à dire qu'ils se contentent du mimimum de reconnaissances possibles dans le texte cible. Leur signification reste la même que pour les quantificateurs avides, seule la notation change. Vous trouverez ci-dessous la notation avide et paresseuse pour chaque quantificateur:

Les accolades:

  • notation avide: {}
  • notation paresseuse: {}?

Le point d'interrogation:

  • notation avide: ?
  • notation paresseuse: ??

L'étoile:

  • notation avide: *
  • notation paresseuse: *?

Le plus:

  • notation avide: +
  • notation paresseuse: +?

Pour voir une utilisation des quantificateur paresseux, vous pouvez comparer ces deux scripts: Avec des quantificateurs avides:

<?php
$chaine = "J'espère que l'année 2004 sera bonne pour vous." ;
$regex  = "#(.*)([0-9]+)(.*)#" ;
 
if(preg_match($regex, $chaine, $matches))
{
    echo "<pre>" ;
    print_r($matches) ;
    echo "</pre>" ;
}//fin if
?>

Avec des quantificateurs paresseux:

<?php
$chaine = "J'espère que l'année 2004 sera bonne pour vous." ;
$regex  = "#(.*?)([0-9]+)(.*)#" ;
 
if(preg_match($regex, $chaine, $matches))
{
    echo "<pre>" ;
    print_r($matches) ;
    echo "</pre>" ;
}//fin if
?>

Et regardez la différence au niveau de la récupération de l'année 2004 ;)

Le reconnaissance la plus à gauche gagne:

En théorie, on dit que la reconnaissance qui à lieu le plus à gauche dans la chaine cible est toujours celle retenue, même si d'autre reconnaissances -mais qui ont lieu plus loin dans la chaine- ont lieu.

Prenons une phrase d'exemple:

  Le portail media box vous souhaites la bienvenue, mais essuyez vos pieds avant d'entrer.

Et maintenant recherchons les mots 'media', 'la', 'pieds', 'entrer'. Nous obtenons ainsi la regex suivante

#entrer|pieds|la|media#

L'ordre est volontairement aléatoire ;). Dans ce cas, le script suivant: QUOTE

<?php
$chaine = "Le portail media box vous souhaite la bienvenue, 
mais essuyez vos pieds avant d'entrer." ;
$regex  = "#entrer|pieds|la|media#" ;
 
if(preg_match($regex, $chaine, $matches))
    echo $matches[0] ;
?>
  media

En effet, même si 'media' est en dernier dans la liste des mots à rechercher, étant donné qu'il se trouve le plus à gauche dans la chaine cible, c'est ce mot qui sera retenu.

Options des expressions régulières

Comme je l'ai dit au début de ce tutorial, une expression régulière peut être composée d'un modèle et d'options, c'est ce que nous allons voir. Une option permet d'influer sur l'interprétation du modèle. De plus il est possible de les cumuler ce qui rend parfois les choses beaucoup plus simple. Toutefois si vous souhaitez ne pas utiliser d'options, sachez que par défaut le modèle s'appliquera à une seule ligne, c'est à dire à une chaîne terminée par \n.

Liste des options possibles pour les PCRE

  • i PCRE_CASELESS Effectue une recherche insensible à la casse.
  • m PCRE_MULTILINE Effectue une recherche multilignes.
  • s PCRE_DOTALL Le méta caractère point '.' remplace n'importe quel caractère, y compris les nouvelles lignes.
  • x PCRE_EXTENDED Permet d'ajouter des commentaires dans les masques. Les commentaires dans ce cas, se notent #commentaire. Notez que seule cette notation fonctionnera: /(chat)#commentaire/x Vous ne pouvez pas utiliser les dièses '#' pour séparer le modèle de vos options, sinon vous risquez d'obtenir une erreur de compilation de l'expressions régulière.
  • E Avec cette option, preg_replace effectue la substitution normale des références arrières dans la chaîne de remplacement, puis l'évalue comme un code PHP, et utilise le résultat pour remplacer la chaîne de recherche. Seule preg_replace utilise cette option.
  • A PCRE_ANCHORED Le motif recherché dans la chaine cible doit correspondre du début à la fin à l'expression régulière.
  • E PCRE_DOLLAR_ENDONLY Le méta-caractère $ ne sera valable qu'à la fin de la chaîne sujet. Sans cette option, $ est aussi valable avant une nouvelle ligne, si cette dernière est le dernier caractère de la chaîne. Cette option est ignorée si l'option m est activée. Il n'y a pas d'équivalent en Perl.
  • S Lorsqu'un masque est utilisé plusieurs fois, cela vaut la peine de passer quelques instants de plus pour l'analyser et optimiser le code pour accélérer les traitements ultérieurs. Cette option force cette analyse plus poussée. Actuellement, cette analyse n'est utile que pour les masques non ancrés, qui ne commencent pas par un caractère fixe.
  • U PCRE_UNGREEDY Cette option inverse la tendance à la gourmandise des expressions régulières. Vous pouvez aussi inverser cette tendance au coup par coup avec un ?. De même, si cette option est activée, le ? rendra gourmand une séquence. Cette option n'est pas compatible avec Perl. Elle peut aussi être mise dans le masque avec l'option ?U .
  • X PCRE_EXTRA Cette option ajoute d'autres fonctionnalités incompatible avec le PCRE de Perl. Tous les antislash suivis d'une lettre qui n'auraient pas de signification particulière cause une erreur, permettant la réservation de ces combinaisons pour des ajouts fonctionnels ultérieurs. Par défaut, comme en Perl, les antislash suivis d'une lettre sans signification particulière sont traités comme des valeurs littérales. Actuellement, cette option ne déclenche pas d'autres fonctions.
  • u PCRE_UTF8 Cette option désactive les fonctionnalités additionnelles de PCRE qui ne sont pas compatibles avec Perl. Les chaînes sont traitées comme des chaînes UTF-8. Cette option est disponible en PHP 4.1.0 et plus récent.

Cette liste et tirée de la documentation PHP, avec quelques modifications personnelles pour certaines options.

Les références arrières: \\chiffre

Comme nous l'avons vu dans la partie traitant les parenthèses, celles-ci permettent de capturer une reconnaissance dans le texte, elle reste stockée en mémoire pour être ensuite réutilisée.

Voyons le fonctionnement avec un exemple:

#(truc)(machin)(bidule)#

Nous avons donc trois groupes de parenthèses, le texte reconnu dans la chaine cible sera donc stocké dans des variables, disponibles ensuite par la notation \\1, \\2, \\3 c'est ce que l'on apelle les références arrières ainsi (truc) sera capturé dans \\1, (machin) dans \\2 et (bidule) dans \\3.

Il existe une règle concernant ces parenthèses capturantes, elles sont numérotées en comptant les parenthèses ouvrantes depuis la gauche. Ce qui peut apparaitre comme une lapalissade est toutefois important.

Prenons un exemple: Quelles sont les références arrières de:

((truc)(machin)(bidule))

Voilà la solution:

  • ( (truc)(machin)(bidule) ) remplit \\1.
  • (truc) remplit \\2.
  • (machin) remplit \\3.
  • (bidule) remplit \\4.

Il existe aussi la notation $1… qui est utilisable dans preg_replace, mais uniquement dans preg_replace,.

Les parenthèses non capturantes: (?:expression)

Comme nous l'avons déjà vu, les parenthèses permettent de capturer un texte, mais parfois c'est inutile, nous avons juste besoin de reconnaitre la séquence qu'elle contient sans pour autant stocker la reconnaissance en mémoire. Il est possible de faire cela avec les parenthèses non capturantes. Elles se distinguent des parenthèses capturantes par la notation ?:, par exemple (?:truc) permet de dire “Je cherche un séquence de caractères, un 't' suivi immédiatement d'un 'r', suivi immédiatement d'un'u', suivi immédiatement d'un 'c', mais je ne veux pas stocker cette reconnaissance en mémoire, je veux qu'elle ait lieu, c'est tout”.

Groupe atomique: (?>expression)

Une reconnaissance atomique se déroule normalement , mais au moment ou elle se termine, c'est à dire au moment ou elle atteint la parenthèse fermante, le texte reconnu à l'intérieur est figé, il y a alors deux options soit le garder, soit le jeter. Ne sachant pas vraiment comme cette méthode fonctionne, ni même comment on peut l'utiliser dans des cas concrets, je ne me risquerais pas à vous donner un exemple, je me contente juste de vous en donner une définition.

Les tests avant/arrières:

Les tests avants ou arrières ne reconnaissent pas de texte, mais peuvent reconnaitre une une position dans le texte cible. Il est ainsi plus pratique de définir que vous voulez tel caractère à telle position.

Les tests avants positifs: (?=expression)

Le test avant positif regarde en avance dans le texte cible, c'est à dire qu'il va vérifier sur la droite si la sous-expression dont il fait partie peut réussir. Voici un exemple de test avant positif: Prenons la phrase

  Bienvenue sur le site Mediabox

et appliquons le modèle suivant:

#Media(?=box)#

Ce modèle signifie littéralement: “Je souhaite trouver le mot Media uniquement s'il est suivi du mot box” autrement dit “Je veux trouver le mot Media uniquement si le mot box est sur sa droite immédiate”.

Vous pouvez tester ce code pour voir par vous même:

<?php
$texte = "Bienvenue sur le site de Mediabox" ;
$pattern = "#Media(?=box)#";
if(preg_match($pattern, $texte, $matches))
    print_r($matches) ;
else
    echo  "rien trouvé" ;
?>

Les test avants négatifs: (?!expression)

Comme le test avant positif, le test avant négatif va regarder sur la droite dans le texte cible, mais en vérifiant si la sous-expression dont il fait partie ne peut réussir.

Les tests arrières positifs: (?<=expression)

Le test arrière positif regarde en arrière dans le texte, c'est à dire qu'il va vérifier sur la gauche si la sous-expression dont il fait partie peut réussir.

Voici un exemple de test arrière positif: Prenons la phrase

  On parle de multimedia

et appliquons le modèle suivant

#(?<=multi)media#

Ce modèle signifie littéralement: “Je souhaite trouver le mot media uniquement s'il est précédé du mot muti” autrement dit “Je veux toruver le mot media uniquement si le mot multi est sur sa gauche immédiate”.

Vous pouvez tester ce code pour voir par vous même:

<?php
$texte = "On parle de multimedia" ;
$pattern = "#(?<=multi)media#" ;
if(preg_match($pattern, $texte, $matches))
    print_r($matches) ;
else
    echo "rien trouvé" ;
?>

Les tests arrières négatifs: (?<!expression)

Comme le test arrière positif, le test arrière négatif va regarder sur la gauche dans le texte cible si la sous-expression dont il fait partie ne peut réussir.

Les tests conditionnels: (?(if) then | else) La strucutre conditionnelle permet d'exprimer un “si, alors, sinon” comme en programmation normale, si le test du if réussi on passe à then sinon on passe à else.

Les limites de mot: \b Les limites de mots reconnaissent un emplacement dans une chaine. On apelle une limite de mot tout caractère qui n'est pas adjacent à un autre caractère normal et non spécial comme par exemple, le point, la virgule, l'espace ou la tabulation, le saut de ligne, la nouvelle ligne….

Les modificateurs de codes: (?modificateur) Avec les PCRE il est possible d'utiliser ce que l'on apelle les modificateurs de codes, ils permettent de de modifier une option de reconnaissance à l'intérieur de l'expression régulière elle même, ainsi vous pouvez par exemple appliquer une insensibilité à la casse pour seulement une partie de votre expressions régulière, ce qui peut-être pratique dans certains cas ;-).

Voici la liste des modificateurs de codes disponibles:

  • i insensibilité à la casse des caractères
  • x permet de reconnaitre le format de commentaire
  • s le point reconnait tout
  • m recherche multilignes

Vous avez donc les possibilités suivantes:

  • (?i…….) la reconnaissance est insensible à la casse lorsque est elle a lieu entre cette paire de parenthèses.
  • (?x……) il est possible de rajouter des commentaires grâce à l'opérateur # dans paire de parenthèses.
  • (?s……) le caractère point reconnait tout entre cette paire de parenthèses.
  • (?m…..) la recherche est multilignes entre cette paire de parenthèses.

C'est la fin de la première partie de ce tutorial, dans la seconde partie nous verrons comment comment construire quelques expressions régulières types.


Tutorial de Qwix