Une fois n'est pas coutume, il y a peu de fonctions concernant les expressions régulières dans PHP. Ces fonctions, au nombre de sept, peuvent être classées en trois groupes :

- des fonctions de recherche de correspondance,
- des fonctions de remplacement de modèles,
- des fonctions de découpage de chaînes.

Les fonctions pour la recherche de correspondance vérifient si une chaîne est conforme ou non à une expression régulière. Il y a deux fonctions dans cette catégorie, qui permettent non seulement de vérifier la correspondance d'une chaîne à un motif, mais également de récupèrer les parties correspondantes aux motifs.

### Recherche simple

La fonction preg_match() est sans doute la plus utilisée de toutes les fonctions d'expression régulière. Elle permet d'abord de vérifier qu'un modèle est trouvé dans une chaîne. Le modèle est le premier paramètre de la fonction, et la chaîne le deuxième. La fonction renvoie TRUE si le modèle est trouvé, FALSE sinon.

L'exemple suivant utilise la fonction preg_match() pour définir si une chaîne correspond au modèle d'une adresse e-mail.

Exemple : recherche simple
<?php require('bib_fonctions.php'); htmlDebut('Recherche simple'); $exp = '/^[a-z][\w\-\.]*@[a-z][\w\-\.]*\.[a-z]{2,6}$/i'; $txt = 'darkounet@lesMechants.com'; if (preg_match($exp, $txt)) { htmlInfo("L'adresse $txt est correcte"); } else { htmlInfo("L'adresse $txt n'est pas bonne"); } $txt = 'yoyo76_lesGentils.com'; if (preg_match($exp, $txt)) { htmlInfo("L'adresse $txt est correcte"); } else { htmlInfo("L'adresse $txt n'est pas bonne"); } htmlFin(); ?>

L'exemple suivant teste différents formats de nombres.

Exemple : recherche simple
<?php require('bib_fonctions.php'); htmlDebut('Recherche simple'); $exp = '/^-?\d{1,4}$|^-?\d{1,4}\.\d{0,2}$/'; verifier($exp, 123.45); verifier($exp, '1234.5'); verifier($exp, ' -12'); verifier($exp, -0.12); verifier($exp, 12.345); verifier($exp, '0a'); //====================================================== function verifier($exp, $txt) { if (preg_match($exp, $txt)) { htmlInfo("$txt est un nombre acceptable"); } else { htmlInfo("$txt n'est pas un nombre acceptable"); } } htmlFin(); ?>

### Récupérer des sous-chaînes

Si notre expression régulière contient des sous-chaînes (définies par des parenthèses ouvrantes et fermantes), la fonction preg_match() peut être utilisée avec un troisième paramètre : le nom d'un variable qui contiendra après exécution de la fonction les captures effectuées. Les sous-chaînes répondant au modèle seront capturées, et renvoyées sous la forme d'un tableau.

Reprenons l'expression qui sert à valider une adresse e-mail :
/^[a-z][\w\-\.]*@[a-z][\w\-\.]*\.[a-z]{2,6}$/i

Cette expression peut être séparée en plusieurs parties :

parties de l'expression régulière

Si nous entourons la partie locale, la partie nom de domaine et la partie grand domaine par des parenthèses, nous pouvons récupèrer ces zones sous la forme d'éléments de tableau.

Essayons donc cette expression régulière :
/^([a-z][\w\-\.]*)@([a-z][\w\-\.]*)\.([a-z]{2,6})$/i

Exemple : récupérer des sous-chaînes
<?php require('bib_fonctions.php'); htmlDebut('Récupérer des sous-chaînes'); $exp = '/^([a-z][\w\-\.]*)@([a-z][\w\-\.]*)\.([a-z]{2,6})$/i'; $txt = 'darkounet@lesMechants.com'; preg_match($exp, $txt, $t); infoTableau($t); htmlFin(); ?>

Le résultat du test montre le tableau créé par la fonction preg_match() dans la variable $t. Le premier élément du tableau est le texte capturé entier. Les éléments suivants sont les différentes sous-chaînes.

Nous pouvons enlever les assertions de début et fin de chaîne pour travailler sur un texte plus complet comme :
"Vous pouvez écrire à francois.piat@univ-fcomte.fr pour féliciter l'auteur de ce cours."

Exemple : récupérer des sous-chaînes
<?php require('bib_fonctions.php'); htmlDebut('Récupérer des sous-chaînes'); $exp = '/([a-z][\w\-\.]*)@([a-z][\w\-\.]*)\.([a-z]{2,6})/i'; $txt = "Vous pouvez écrire à francois.piat@univ-fcomte.fr pour féliciter l'auteur de ce cours."; preg_match($exp, $txt, $t); infoTableau($t); htmlFin(); ?> </html>

Que se passe-t-il quand le texte à examiner est le suivant :
"Vous pouvez écrire à francois.piat@univ-fcomte.fr ou à fpiat@femto-st.fr pour féliciter l'auteur de ce cours.".
Nous avons ici deux adresses email, et on devrait avoir le tableau suivant :

Indice | Valeur
0 | francois.piat@univ-fcomte.fr
1 | francois.piat
2 | univ-fcomte
3 | fr
4 | fpiat@femto-st.fr
5 | fpiat
6 | femto-st
7 | fr

Exemple : récupérer des sous-chaînes
<?php require('bib_fonctions.php'); htmlDebut('Récupérer des sous-chaînes'); $exp = '/([a-z][\w\-\.]*)@([a-z][\w\-\.]*)\.([a-z]{2,6})/i'; $txt = "Vous pouvez écrire à francois.piat@univ-fcomte.fr ou à fpiat@femto-st.fr pour féliciter l'auteur de ce cours."; preg_match($exp, $txt, $t); infoTableau($t); htmlFin(); ?>

Le résultat du test n'est pas celui que nous attendons. Le tableau ne montre que la première adresse email trouvée. Le code n'est pas en cause et fonctionne parfaitement. En effet, la fonction preg_match() s'arrête à la première occurence trouvée pour le modèle. Pour récupèrer toutes les occurences su modèle, il faut utiliser une autre fonction.

### Récupérer toutes les occurences

La fonction preg_match_all() fonctionne comme preg_match() à la différence qu'elle recherche le modèle autant de fois que c'est possible, et qu'elle ne s'arrête pas à la première concordance trouvée.

Après l'exécution de la fonction, la variable utilisée pour stocker le résultat contiendra un tableau à deux dimensions, classé par correspondance ou par ordre des parenthèse selon la valeur du quatrième paramètre de la fonction preg_match_all(). Vous n'avez rien compris ? Alors passez aux exemples.

Exemple : récupérer des sous-chaînes
<?php require('bib_fonctions.php'); htmlDebut('Récupérer des sous-chaînes'); $exp = '/([a-z][\w\-\.]*)@([a-z][\w\-\.]*)\.([a-z]{2,6})/i'; $txt = "Vous pouvez écrire à francois.piat@univ-fcomte.fr ou à piat@lifc.univ-fcomte.fr pour féliciter l'auteur de ce cours."; htmlInfo('Classées par occurence'); preg_match_all($exp, $txt, $t, PREG_SET_ORDER); infoTableau($t); htmlInfo('Classées par ordre des parenthèses'); preg_match_all($exp, $txt, $t, PREG_PATTERN_ORDER); infoTableau($t); htmlFin(); ?>

Comme le montre le test, l'utilisation de la constante prédéfinie PREG_SET_ORDER offre ici le meilleur moyen pour traiter au mieux les résultats de la fonction preg_match_all().

### Exercice : extraire les liens d'une page HTML

Affichez la liste des liens inclus dans la page à l'adresse http://www.php.net (vous devez avoir une connexion Internet ouverte). Afficher simplement la liste avec la fonction print_r() ou avec la fonction infoTableau() comme dans les exemples du cours.

La fonction file_get_contents vous permet de récupérer le contenu d'un fichier. Par exemple :

$codeHTML = file_get_contents('http://www.php.net');

Rappel : un lien est la valeur de l'attribut href.

Une solution possible

Une première solution toute simple.

Exercice : extraire les liens d'une page HTML
<?php require('bib_fonctions.php'); htmlDebut('Extraire les liens d\'une page HTML'); $CodeHTML = file_get_contents('http://www.php.net'); $exp = '/ href="(.*?)"/is'; preg_match_all($exp, $CodeHTML, $t, PREG_PATTERN_ORDER); infoTableau($t); htmlFin(); ?>

Cette première solution capture absolument tous éléments liés, même ceux qui ne sont pas des liens cliquables (feuilles de styles par exemple). En plus, la valeur de l'attribut href doit être entourée avec des guillemets doubles, ce qui n'est pas toujours le cas.

Nous pouvons améliorer l'expression comme ça :
<a[\s]+[^>]*?href[\s]?=[\s\"\']+(.*?)[\"\']+.*?>/is

<a | la chaîne littérale <a
[\s]+ | 1 ou plusieurs caractères d'espacement
[^>]*? | n'importe quel caractère sauf un >, non gourmand
href | la chaîne littérale href
[\s]? | 0 ou plusieurs caractères d'espacement
= | la chaîne littérale =
[\s\"\']+ | 1 ou plusieurs caractères d'espacement ou " ou '
(.*?) | n'importe quel caractère n'importe combien de fois, capturé
[\s\"\']+ | 1 ou plusieurs caractères d'espacement ou " ou '
.*? | n'importe quel caractère n'importe combien de fois, non gourmand
> | la chaîne littérale >
i | ignore la casse
s | le point reconnaît les sauts de ligne

Exercice : extraire les liens d'une page HTML
<?php require('bib_fonctions.php'); htmlDebut('Extraire les liens d\'une page HTML'); $CodeHTML = file_get_contents('http://www.php.net'); $exp = '/<a[\s]+[^>]*?href[\s]?=[\s\"\']+(.*?)[\"\']+.*?>/is'; preg_match_all($exp, $CodeHTML, $t, PREG_PATTERN_ORDER); htmlInfo('Liens complets'); foreach ($t[0] as $lien) { echo '<br>', htmlentities($lien); } htmlInfo('Cible des liens'); infoTableau($t[1]); htmlFin(); ?>