Articles web

Nos articles concernant les techniques web sont centrés sur des solutions pratiques qui mettent en œuvre, le plus souvent, notre framework web : Vae Soli!

Des articles généraux sont également fournis dans le respect des standards du web.

Tous nos articles web sont disponibles sous le couvert de la licence Icône Creative Commons Creative Commons — Paternité - pas de modification.

2013-02-10 à 20:59:08

Sans chichis, voici quelques 34 expressions régulières à utiliser en PHP

regex, expression régulière, PHP, regex pour parser HTML

2012-06-02 – 20:56

2012-06-02 – 20:56

2013-02-10 – 20:59

Voici un petit ensemble de 34 expressions régulières que vous pouvez utiliser dans votre code source afin de traiter un ensemble de petits problèmes de parsing. Vous avez le droit d'utiliser toutes les expressions régulières publiées sur cette page dans le respect de la licence Creative Commons - Attribution 3.0 non transposé (CC BY 3.0).

Dans nos exemples, le code HTML à parser, via l'expression régulière, se trouve dans la variable $szHTML; les résultats trouvés par utilisation de la regex sont mis dans un tableau dont le nom est systématiquement $aMatch.

Si vous avez des remarques ou des suggestions, n'hésitez pas à les formuler grâce à la saisie de commentaires disponible dans le bas de l'article.

REGEX #1. Extraction du DOCTYPE

if ( preg_match( '/<!DOCTYPE +(.*?)>/si',$szHTML,$aMatch ) )
{
    var_dump( $aMatch );
    echo trim( $aMatch[1] );
}

REGEX #2. Élimination du DOCTYPE

$szHTML = preg_replace( '/<!DOCTYPE.*?>/si','',$szHTML );

REGEX #3. Extraction du charset

if ( preg_match( '/<meta +http-equiv="content-type" +content="(.+?)" *\/>/si',$szHTML,$aMatch ) )
{
    var_dump( $aMatch );
    echo trim( $aMatch[1] );
}

REGEX #4. Extraction de l'URL canonique

if ( preg_match( '/<link +?rel=["\']canonical["\'] +?href=["\'](.+?)["\'].*?>/si',$szHTML,$aMatch ) )
{
    var_dump( $aMatch );
    echo trim( $aMatch[1] );
}

REGEX #5. Extraction des headings d'une page (<h1> à <h6>)

if ( preg_match_all( '%<h([1-6])[^>]*>(.*?)</h\1>%si',$szHTML,$aMatch,PREG_PATTERN_ORDER ) )
{
    var_dump( $aMatch );
}

REGEX #6. Extraction du code langue d'une page (multiples stratégies)

if ( preg_match( '/<meta +?http-equiv="content-language" +content="(.+?)" *\/>/si',$szHTML,$aMatch ) )
{
    echo $aMatch[1];
}
elseif ( preg_match( '/<html +?lang="(.*?)".*?>/si',$szHTML,$aMatch ) )
{
    echo $aMatch[1];
}
elseif ( preg_match( '/<html.+?xml:lang="(.*?)".*?>/si',$szHTML,$aMatch ) )
{
    echo $aMatch[1];
}
elseif ( preg_match( '/<meta +?name=["\']DC\.language["\'] +?content=["\'](.*?)["\'] *?\/>/si',$szHTML,$aMatch ) )
{
    echo $aMatch[1];
}

REGEX #7. Extraction des liens d'une page (<a>...</a>)

if ( preg_match_all( '%<a[^>]*href=(["\'])(.*?)\1[^>]*>.*?</a>%si',$szHTML,$aMatch,PREG_PATTERN_ORDER ) )
{
    // Les href se trouvent dans $aMatch[2]
    var_dump( $aMatch );
}

REGEX #8. Extraction du titre d'une page

if ( preg_match( '%<title[^>]*>(.*?)</title>%si',$szHTML,$aMatch ) )
{
    var_dump( $aMatch );
    echo trim( $aMatch[1] );
}

REGEX #9. Extraction de l'URL de base d'une page

if ( preg_match( '/<head[^>]*?>.*?<base.*?href="(.+?)".*?\/>.*?<\/head>/si',$szHTML,$aMatch ) )
{
    var_dump( $aMatch );
    echo trim( $aMatch[1] );
}

REGEX #10. Élimination des javascripts

$szHTML = preg_replace( '%<script[^>]*>(.*?)</script>%si','',$szHTML );

REGEX #11. Élimination des styles

$szHTML = preg_replace( '%<style[^>]*>(.*?)</style>%si','',$szHTML );

REGEX #12. Élimination des commentaires, des tags, des scripts et des styles

$szHTML = preg_replace( '%</?[a-z][a-z0-9]*[^<>]*>|<!--.*?-->%si','',$szHTML );

REGEX #13. Remplacement des multiples occurrences d'espaces par un seul espace

En fait, nous remplaçons les multiples occurrences d'une classe spéciale : les whitespaces, c'est-à-dire les espaces, les tabulations, les retours à la ligne. C'est à cela que correspond la classe \s de l'expression régulière. Chaque whitespace est remplacé par un seul espace.

$szHTML = preg_replace( '/\s{2,}/',' ',$szHTML ) );

REGEX #14. Élimination des caractères de ponctuation

$szHTML = preg_replace( '/[[:punct:]]/si','',$szHTML );

REGEX #15. Matching d'une date au format YYYYMMDD (20ème siècle ou 21ème siècle)

if ( preg_match( '/(19|20)[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])/',$szHTML ) )
{
    echo 'I have a match';  // Case of 20120603
}
else
{
    echo 'No match found';  // Case of 2012-06-03
}
if ( preg_match( '%([0-5][0-9])[0-9]{2}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])%',$szHTML ) )
{
    echo 'I have a match';  // Case of 2012-06-03, 2012 06 03, 2012/06/03, or 2012.06.03
}
else
{
    echo 'No match found';
}

REGEX #16. Déterminer si on a affaire à un fichier XML

if ( preg_match( '/^<\?xml(.*)?\?>/',$szHTML,$aMatch ) )
{
    echo 'XML';
    var_dump( $aMatch );
}
else
{
    echo 'No XML';
}

REGEX #17. Déterminer si on a affaire à un fichier PDF

if ( preg_match( '/^%PDF/',$szHTML ) )
{
    echo 'PDF';
}

REGEX #18. Déterminer si on a affaire à un fichier JPG

if ( preg_match( '/^\xFF\xD8\xFF/',$szHTML ) )
{
    echo 'JPG';
}

REGEX #19. Déterminer si on a affaire à un fichier PNG

if ( preg_match( '/^\x89\x50\x4E\x47/',$szHTML ) )
{
    echo 'PNG';
}

REGEX #20. Déterminer si on a affaire à un fichier GIF (GIF89a ou GIF87a)

if ( preg_match( '/^\x47\x49\x46\x38[\x37\x39]\x61/',$szHTML ) )
{
    echo 'GIF';
}

REGEX #21. Déterminer si on a affaire à un fichier ZIP

if ( preg_match( '/^\x50\x4B\x03\x04\x14\x00/',$szHTML ) )
{
    echo 'ZIP';
}

REGEX #22. Pattern Google Analytics

if ( ( preg_match('/<script[^>]*>.*?google-analytics\.com\/ga\.js.*?<\/script>/si',$szHTML         ) ) &&
     ( preg_match( '/["\'](UA-\d{6,9}-\d{1})["\']/si'                             ,$szHTML,$aMatch ) )
   )
{
    echo 'Google Analytics identifer: ' . $aMatch[1];
}
else
{
    echo 'No Google Analytics found';
}

REGEX #23. Détermination de la présence de Javascript dans le href d'un lien

La variable testée, ici $szURL, équivaut typiquement à la valeur du href trouvée dans une balise <a>…</a> (doubles ou simples guillemets inclus dans la valeur du href).

if ( preg_match('/["\']javascript:[[:alnum:]]*?\((.*?)\).*?["\']/si',$szURL,$aMatch ) )
{
    echo "Javascript detected in {$szURL}";
}
else
{
    echo "No Javascript detected in {$szURL}";
}

REGEX #24. Variation sur la détermination de la présence de Javascript dans le href d'un lien

La variable testée, ici $szURL, équivaut typiquement à la valeur du href trouvée dans une balise <a>…</a> dépouillée de ces simples ou doubles guillemets. On teste immédiatement si le début de la chaîne commence par 'javascript:'.

if ( preg_match('/^javascript:[[:alnum:]]*?\((.*?)\)/si',$this->szURL,$aMatch ) )
{
    echo "Javascript detected in {$szURL}";
}
else
{
    echo "No Javascript detected in {$szURL}";
}

REGEX #25. Parsing d'une URL (protocole, domaine, ressource)

function URL_Parse( $szURL )
/*------------------------*/
{
    $aURL               = array();

    $aURL['path']       =
    $aURL['domain']     =
    $aURL['protocol']   = '';

    if ( preg_match( '/\b((?P<protocol>http|https|ftp):\/\/)?(?P<domain>[-A-Z0-9.]+)(?P<path>\/[-A-Z0-9+&@#\/%=~_|!:,.;]*)?/i',$szURL,$aMatch ) )
    {
        $aURL['protocol']   = isset( $aMatch['protocol'] ) ? $aMatch['protocol'] : '';
        $aURL['domain']     = isset( $aMatch['domain']   ) ? $aMatch['domain']   : '';
        $aURL['path']       = isset( $aMatch['path']     ) ? $aMatch['path']     : '';
    }

    return ( $aURL );
}

REGEX #26. Parsing d'un domaine (sous-domaine, domaine, TLD)

function URL_ParseDomain( $szDomain )
/*---------------------------------*/
{
    $aURL               = array();

    $aURL['tld']        =
    $aURL['domain']     =
    $aURL['subdomain']  = '';

    if ( preg_match( '/(?P<subdomain>[[:alnum:]]+?)?\.(?P<domain>.+?)\.(?P<tld>.{2,})/i',$szDomain,$aMatch ) )
    {
        $aURL['subdomain']  = isset( $aMatch['subdomain'] ) ? $aMatch['subdomain']  : '';
        $aURL['domain']     = isset( $aMatch['domain']    ) ? $aMatch['domain']     : '';
        $aURL['tld']        = isset( $aMatch['tld']       ) ? $aMatch['tld']        : '';
    }

    return ( $aURL );
}

REGEX #27. Parsing d'une heure (HH[:MM[:SS]])

Cette expression régulière est un rien spéciale en ce qu'elle vérifie que les différentes parts restent dans les limites possibles d'une heure : de 0 à 23 pour les heures, de 0 à 59 pour les minutes et les secondes. C'est d'ailleurs sur base de cette expression régulière que nous avons créé la fonction TIM_2Array() de Vae Soli! ci-dessous :

function TIM_2Array( $szTime,$szPart = null )
/*-----------------------------------------*/
{
    $aParts = array();                               /* Return value of the function */

    $aParts['sec']  =                                /* Prepare associative array */
    $aParts['min']  = 
    $aParts['hour'] = 
    '';

    if ( preg_match( '/(?P<hour>0[0-9]|1[0-9]|2[0-3])(:??(?P<min>0[0-9]|[0-5][0-9])(:??(?P<sec>0[0-9]|[0-5][0-9]))?)?/',$szTime,$aMatch ) )
    {
        if ( isset( $aMatch['hour'] ) )                     
            $aParts['hour'] = $aMatch['hour'];       /* Hours */
        if ( isset( $aMatch['min'] ) )               
            $aParts['min'] = $aMatch['min'];         /* Minutes*/
        if ( isset( $aMatch['sec'] ) )               
            $aParts['sec'] = $aMatch['sec'];         /* Seconds */
    }

    if ( ! is_null( $szPart ) && isset( $aParts[$szPart] ) )
    {
        return ( $aParts[$szPart] );                 /* Return part that is requested */
    }
    else
    {
        return ( $aParts );                          /* Return result to caller */
    }
}

REGEX #28. Capture d'un numéro de TVA belge

Dans cet exemple, la variable testée est $szStr.

$szStr = "BE 0878.127.142";
if ( preg_match( '/BE *?(?P<vat>(0)?\d{3}\.??\d{3}\.??\d{3})/i',$szStr,$aMatch ) )
{
    echo "<p>TVA = {$aMatch['vat']}</p>";
}

REGEX #29. Capture de n'importe quel tag HTML

$szTag = quotemeta( $szTag );           /* Example 'h2' */
if ( preg_match_all( "/<{$szTag}[^>]*>(.*?)<\/{$szTag}>/si",$szHTML,$aMatch,PREG_PATTERN_ORDER ) )
{
    var_dump( $aMatch );
}

REGEX #30. Détecter les géo-coordonnées d'une page Web (meta) (geo.position)

if ( preg_match( '/<meta *?name=(["\'])geo\.position\1 *?content=(["\'])(?P<lat>\d{1,}?(\.\d{1,}?)?);(?P<long>\d{1,}?(\.\d{1,}?)?)\2.*?>/si',$this->szHTML,$aMatch ) )
{
    echo $aMatch['lat'];
    echo $aMatch['long'];
}

REGEX #31. Détecter les géo-coordonnées d'une page Web (meta) (geo.placename et geo.region)

if ( preg_match( '/<meta *?name=(["\'])geo\.placename\1 *?content=(["\'])(?P<tag>.*?)\2.*?>/si',$this->szHTML,$aMatch ) )
{
    echo trim( $aMatch['tag'] );
}

if ( preg_match( '/<meta *?name=(["\'])geo\.region\1 *?content=(["\'])(?P<tag>.*?)\2.*?>/si',$this->szHTML,$aMatch ) )
{
    echo trim( $aMatch['tag'] );
}

REGEX #32. Détecter les géo-coordonnées d'une page Web (meta) via l'ICBM(ICBM)

if ( preg_match( '/<meta *?name=(["\'])ICBM\1 *?content=(["\'])(?P<lat>\d{1,}?(\.\d{1,}?)?),(?P<long>\d{1,}?(\.\d{1,}?)?)\2.*?>/si',$this->szHTML,$aMatch ) )
{
    echo $aMatch['lat'];
    echo $aMatch['long'];
}

REGEX #33. Valider un nombre à virgule flottante (float)

if ( preg_match( '/(?P<num>[+-]?\b[0-9]*\.?[0-9]+\b)/',$szHTML,$aMatch ) )
{
    echo $aMatch['num'];
}

REGEX #34. Liste des attribut trouvés dans un tag

if ( preg_match_all( '/([[:alnum:]_]*?)=(["\'])(.*?)\2/i',$szTag,$aMatch,PREG_PATTERN_ORDER ) )
{
    var_dump( $aMatch );
}