IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Fonction preg_match ne retourne pas le résultat escompté


Sujet :

Langage PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 718
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 718
    Par défaut Fonction preg_match ne retourne pas le résultat escompté
    Bonjour,
    J'ai le code html suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <div class="blockImg imgRight">
    	<img src="customs/2/pictures/home.png">
    	<figcaption>Une légende</figcaption>
    </div>
    De ce code, je souhaite extraire:
    1. imgRight (ou imgLeft)
    2. 'home.png'
    3. 'Une légende'

    Pour commencer, j'ai essayé ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $block = file_get_contents($customDir.'blockImg.php');
     preg_match("#imgRight|imgLeft#", $block, $matches, PREG_OFFSET_CAPTURE);
    var_dump($matches);		// retourne 1
    Je voudrais que $matches retourne imgRight ou imgLeft selon le cas.
    EDIT: Correction d'une erreur dans le code.
    EDIT2: J'ai modifié mon code comme ceci: $matches = preg_match("#<div class='blockImg (.+)'>#", $block, $matches, PREG_OFFSET_CAPTURE); // retourne 0 qui retourne 0.

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2022
    Messages
    457
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2022
    Messages : 457
    Par défaut
    Bonjour,
    Quelque chose comme ceci ?
    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    <?php
    // Extraire imgRight ou imgLeft
    preg_match("#<div class=\"blockImg (imgRight|imgLeft)\">#", $block, $matches);
    $imgClass = $matches[1] ?? null;
     
    // Extraire le nom du fichier image
    preg_match("#<img src=\"customs/2/pictures/([^\"]+)\">#", $block, $matches);
    $imgSrc = $matches[1] ?? null;
     
    // Extraire la légende
    preg_match("#<figcaption>([^<]+)</figcaption>#", $block, $matches);
    $figcaption = $matches[1] ?? null;
     
    // Afficher les résultats
    var_dump($imgClass);  // imgRight ou imgLeft
    var_dump($imgSrc);    // home.png
    var_dump($figcaption); // Une légende
    ?>


    Edit : Ton code il renvoie pas 1 mais ca
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    array(1) { [0]=> array(2) { [0]=> string(8) "imgRight" [1]=> int(21) } }
    Cdt

  3. #3
    Membre éprouvé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 718
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 718
    Par défaut
    Merci, c'est parfait mais pourquoi écrire ([^\"]+) ou ([^<]+) plutôt qu'un simple (.+) qui marche aussi bien?

  4. #4
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    3 013
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 3 013
    Par défaut
    Attaquer directement du html avec des fonctions de string ou des regex est un mésusage de celles-ci. Les fonctions de chaînes sont très précises et même si les regex sont plus flexibles, elles restent assez désarmées face à la souplesse de la syntaxe du html.

    Quand bien même ton html est généré automatiquement et est censé avoir toujours la même forme et que tu obtiennes la ou les patterns adéquates, le jour où tu décides de modifier d'ajouter une classe, un élément, un attribut... bref à la moindre modification, tu devras recommencer.

    D'autre part, le html est un langage structuré, donc autant t'appuyer sur cette structure. En utilisant le DOM, tu peux exprimer tes demandes en manipulant des noms de balises et d'attributs ainsi que la structure du document. Ce qui en fait une solution robuste.

    Un exemple: démo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    $html = <<<'HTML'
    <div class="blockImg imgRight">
    	<img src="customs/2/pictures/home.png">
    	<figcaption>Une légende</figcaption>
    </div>
    HTML;
     
    // on ajoute la structure manquante pour préciser l'encodage
    $html = <<<HTML
    <html><head><meta charset="utf-8"/></head><body>$html</body></html>
    HTML;
     
    $dom = new \DOMDocument;
    $dom->loadHTML($html, LIBXML_NOERROR);
     
    $context = $dom->getElementsByTagName('div')[0];
     
    $xp = new \DOMXPath($dom);
     
    // on extrait la valeur de l'attribut class tout en vérifiant la présence de la classe "blockImg"
    $classAttrValue = $xp->evaluate( 
        'string(@class[contains(concat(" ", normalize-space(.), " "), " blockImg ")])',
        $context
    );
     
    if ($classAttrValue && preg_match('~ \b img (?: Right | Left ) \b ~x', $classAttrValue, $m)) {
        $class = $m[0];
        $src = $xp->evaluate('string(img/@src)', $context);
        $filename = basename($src);
        $caption = $xp->evaluate('string(figcaption)', $context);
     
        echo $class, PHP_EOL, $src, PHP_EOL, $filename, PHP_EOL, $caption, PHP_EOL;
    }
    C'est juste une manière de faire, rien ne t'oblige à utiliser XPATH, tu peux aussi le faire juste avec les méthodes de DOMNode, DOMAttr, etc.




    Avec PHP 8.4.1, on peut utiliser aussi \Dom\HTMLDocument qui gère correctement HTML 5 et évite certaines complications: l'encodage est en UTF-8 par défaut, on peut utiliser les querySelectors (ce qui est à la mode mais pas toujours pratique), la propriété \Dom\Element::$classList qui renvoie un object \Dom\TokenList avec une méthode contains() (et donc qui évite de découper l'attribut class soi-même).

    avec XPATH: démo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $html = <<<'HTML'
    <div class="blockImg imgRight">
    	<img src="customs/2/pictures/home.png">
    	<figcaption>Une légende</figcaption>
    </div>
    HTML;
     
    $dom = \Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR | \DOM\HTML_NO_DEFAULT_NS);
     
    $xp = new \Dom\XPath($dom);
     
    $context = $dom->getElementsByTagName('div')[0];
    $classList = $context->classList;
     
    if ($classList->contains('blockImg') and $classList->contains('imgRight') || $classList->contains('imgLeft')) {
        $class = $classList->contains('imgRight') ? 'imgRight' : 'imgLeft';
        $src = $xp->evaluate('string(img/@src)', $context);
        $caption = $xp->evaluate('string(figcaption)', $context);
     
        echo $class, PHP_EOL, $src, PHP_EOL, $caption, PHP_EOL;
    }
    À noter que HTML 5 prend en compte des espaces de noms, c'est la raison pour laquelle j'ai utilisé l'option \DOM\HTML_NO_DEFAULT_NS pour ne pas avoir à préciser l'espace de nom par défaut pour chaque tag dans la requête XPath. Exemple sans cette option:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $xp->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml');
    // ...
    $caption = $xp->evaluate('string(xhtml:figcaption)', $context);



    Avec les querySelectors: démo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    $html = <<<'HTML'
    <div class="blockImg imgRight">
    	<img src="customs/2/pictures/home.png">
    	<figcaption>Une légende</figcaption>
    </div>
    HTML;
     
    $dom = \Dom\HTMLDocument::createFromString($html, LIBXML_NOERROR);
     
    $divNode = $dom->querySelector('div.blockImg');
     
    $classList = $divNode?->classList;
     
    if ($divNode and $classList->contains('imgRight') || $classList->contains('imgLeft')) {
        $class = $classList->contains('imgRight') ? 'imgRight' : 'imgLeft';
        $src = $divNode->querySelector('img')->getAttribute('src');
        $caption = $divNode->querySelector('figcaption')->textContent;
     
        echo $class, PHP_EOL, $src, PHP_EOL, $caption, PHP_EOL;
    }
    Pour l'instant la doc PHP n'est pas à jour sur ces fonctionnalités, mais vous pouvez trouver des renseignements sur le rfc de ext-dom.

  5. #5
    Membre éprouvé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 718
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 718
    Par défaut
    Merci pour ce cours complet. J'ai déjà utilisé le DOM en JavaScript mais il faut que je creuse davantage en PHP. Provisoirement, je vais garder la solution regex et je note d'approfondir la solution DOM en fin d'avancement du projet.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] fonction qui ne retourne pas de valeur
    Par chuspyto dans le forum VB.NET
    Réponses: 5
    Dernier message: 13/05/2013, 23h13
  2. Réponses: 7
    Dernier message: 22/04/2010, 16h45
  3. fonction qui ne retourne pas de valeur
    Par 241987 dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 16/07/2009, 09h41
  4. Réponses: 5
    Dernier message: 27/01/2009, 11h46
  5. Fonction ne retournant pas toujours une valeur
    Par mastochard dans le forum C
    Réponses: 14
    Dernier message: 25/05/2006, 13h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo