Question

Je souhaite créer une page dans laquelle toutes les images qui résident sur mon site Web sont répertoriées avec un titre et une représentation alternative.

J'ai déjà écrit un petit programme pour trouver et charger tous les fichiers HTML, mais je suis maintenant bloqué sur la façon d'extraire src, title et alt de ce HTML:

<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny" />

Je suppose que cela devrait être fait avec une regex, mais puisque l'ordre des tags peut varier et que j'ai besoin de tous, je ne sais pas vraiment comment analyser cela de manière élégante (je pourrais le faire caractère dur par un caractère, mais c'est douloureux).

Était-ce utile?

La solution

EDIT: maintenant que je sais mieux

Utiliser regexp pour résoudre ce type de problème est une mauvaise idée et mènera probablement à un code non maintenable et peu fiable. Il vaut mieux utiliser un analyseur HTML .

Solution avec l'expression rationnelle

Dans ce cas, il est préférable de scinder le processus en deux parties:

  • obtenir toutes les balises img
  • extraire leurs métadonnées

Je suppose que votre document n'est pas xHTML strict, vous ne pouvez donc pas utiliser un analyseur XML. PAR EXEMPLE. avec le code source de cette page Web:

/* preg_match_all match the regexp in all the $html string and output everything as 
an array in $result. "i" option is used to make it case insensitive */

preg_match_all('/<img[^>]+>/i',$html, $result); 

print_r($result);
Array
(
    [0] => Array
        (
            [0] => <img src="/Content/Img/stackoverflow-logo-250.png" width="250" height="70" alt="logo link to homepage" />
            [1] => <img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />
            [2] => <img class="vote-down" src="/content/img/vote-arrow-down.png" alt="vote down" title="This was not helpful (click again to undo)" />
            [3] => <img src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt="gravatar image" />
            [4] => <img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />

[...]
        )

)

Ensuite, nous obtenons tous les attributs de la balise img avec une boucle:

$img = array();
foreach( $result as $img_tag)
{
    preg_match_all('/(alt|title|src)=("[^"]*")/i',$img_tag, $img[$img_tag]);
}

print_r($img);

Array
(
    [<img src="/Content/Img/stackoverflow-logo-250.png" width="250" height="70" alt="logo link to homepage" />] => Array
        (
            [0] => Array
                (
                    [0] => src="/Content/Img/stackoverflow-logo-250.png"
                    [1] => alt="logo link to homepage"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                )

            [2] => Array
                (
                    [0] => "/Content/Img/stackoverflow-logo-250.png"
                    [1] => "logo link to homepage"
                )

        )

    [<img class="vote-up" src="/content/img/vote-arrow-up.png" alt="vote up" title="This was helpful (click again to undo)" />] => Array
        (
            [0] => Array
                (
                    [0] => src="/content/img/vote-arrow-up.png"
                    [1] => alt="vote up"
                    [2] => title="This was helpful (click again to undo)"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                    [2] => title
                )

            [2] => Array
                (
                    [0] => "/content/img/vote-arrow-up.png"
                    [1] => "vote up"
                    [2] => "This was helpful (click again to undo)"
                )

        )

    [<img class="vote-down" src="/content/img/vote-arrow-down.png" alt="vote down" title="This was not helpful (click again to undo)" />] => Array
        (
            [0] => Array
                (
                    [0] => src="/content/img/vote-arrow-down.png"
                    [1] => alt="vote down"
                    [2] => title="This was not helpful (click again to undo)"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                    [2] => title
                )

            [2] => Array
                (
                    [0] => "/content/img/vote-arrow-down.png"
                    [1] => "vote down"
                    [2] => "This was not helpful (click again to undo)"
                )

        )

    [<img src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG" height=32 width=32 alt="gravatar image" />] => Array
        (
            [0] => Array
                (
                    [0] => src="http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
                    [1] => alt="gravatar image"
                )

            [1] => Array
                (
                    [0] => src
                    [1] => alt
                )

            [2] => Array
                (
                    [0] => "http://www.gravatar.com/avatar/df299babc56f0a79678e567e87a09c31?s=32&d=identicon&r=PG"
                    [1] => "gravatar image"
                )

        )

   [..]
        )

)

Les expressions régulières nécessitent beaucoup de temps de traitement; vous souhaiterez donc peut-être mettre en cache cette page. Si vous n’avez pas de système de cache, vous pouvez modifier le vôtre en utilisant ob_start et chargement / enregistrement depuis un fichier texte.

Comment ça marche?

Tout d'abord, nous utilisons preg_ match_ all , une fonction qui obtient toutes les chaînes correspondant au modèle et les place dans son troisième paramètre.

Les expressions rationnelles:

<img[^>]+>

Nous l’appliquons sur toutes les pages Web html. Il peut être lu comme chaque chaîne commençant par & "; <img &" ;, ne contient pas & "; & Gt; &"; char et se termine par un > .

(alt|title|src)=("[^"]*")

Nous l’appliquons successivement sur chaque balise img. Il peut être lu comme chaque chaîne commençant par & "; Alt &"; & "Title &"; ou & "; src &"; puis un & ";" = & "; puis un" & "; ", un tas de choses qui ne sont pas" & "; 'et se termine par un' " '. Isolez les sous-chaînes entre () .

Enfin, chaque fois que vous souhaitez gérer les expressions rationnelles, il est utile de disposer de bons outils pour les tester rapidement. Consultez ce testeur d'expressions rationnelles en ligne .

EDIT: répond au premier commentaire.

Il est vrai que je n'ai pas pensé aux personnes (espérons-le, peu nombreuses) utilisant des guillemets simples.

Eh bien, si vous utilisez seulement ', remplacez simplement tous les " par '.

Si vous mélangez les deux. Commencez par vous gifler :-), puis essayez d’utiliser (& Quot; | ') à la place ou & Quot; et [^ & # 248;] pour remplacer [^ "].

Autres conseils

$url="http://example.com";

$html = file_get_contents($url);

$doc = new DOMDocument();
@$doc->loadHTML($html);

$tags = $doc->getElementsByTagName('img');

foreach ($tags as $tag) {
       echo $tag->getAttribute('src');
}

Juste pour donner un petit exemple d'utilisation de la fonctionnalité XML de PHP pour la tâche:

$doc=new DOMDocument();
$doc->loadHTML("<html><body>Test<br><img src=\"myimage.jpg\" title=\"title\" alt=\"alt\"></body></html>");
$xml=simplexml_import_dom($doc); // just to make xpath more simple
$images=$xml->xpath('//img');
foreach ($images as $img) {
    echo $img['src'] . ' ' . $img['alt'] . ' ' . $img['title'];
}

J'ai utilisé la méthode DOMDocument::loadHTML() car cette méthode peut gérer la syntaxe HTML et ne force pas le document d'entrée à être XHTML. Strictement parlant, la conversion en SimpleXMLElement n’est pas nécessaire - elle simplifie l’utilisation de xpath et des résultats de xpath plus simples.

S'il s'agit de XHTML, votre exemple est: vous n'avez besoin que de XML simple.

<?php
$input = '<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny"/>';
$sx = simplexml_load_string($input);
var_dump($sx);
?>

Sortie:

object(SimpleXMLElement)#1 (1) {
  ["@attributes"]=>
  array(3) {
    ["src"]=>
    string(22) "/image/fluffybunny.jpg"
    ["title"]=>
    string(16) "Harvey the bunny"
    ["alt"]=>
    string(26) "a cute little fluffy bunny"
  }
}

Le script doit être modifié comme ceci

foreach( $result[0] as $img_tag)

parce que preg_match_all renvoie un tableau de tableaux

Vous pouvez utiliser simplehtmldom . La plupart des sélecteurs jQuery sont pris en charge dans simplehtmldom. Un exemple est donné ci-dessous

// Create DOM from URL or file
$html = file_get_html('http://www.google.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>'; 

J'ai utilisé preg_match pour le faire.

Dans mon cas, j'avais une chaîne contenant exactement une balise <img> (et aucune autre balise) fournie par Wordpress et j'essayais d'obtenir l'attribut src afin de pouvoir l'exécuter via timthumb.

// get the featured image
$image = get_the_post_thumbnail($photos[$i]->ID);

// get the src for that image
$pattern = '/src="([^"]*)"/';
preg_match($pattern, $image, $matches);
$src = $matches[1];
unset($matches);

Dans le modèle permettant de saisir le titre ou l'alt, vous pouvez simplement utiliser $pattern = '/title="([^"]*)"/'; pour saisir le titre ou <=> pour saisir l'alt. Malheureusement, mon expression rationnelle n’est pas assez bonne pour saisir les trois (alt / title / src) en un seul passage.

Voici une fonction PHP que j'ai combinée avec toutes les informations ci-dessus dans un but similaire, à savoir ajuster les propriétés de largeur et de longueur de balise d'image à la volée ... un peu maladroit, peut-être, mais semble fonctionner de manière fiable:

function ReSizeImagesInHTML($HTMLContent,$MaximumWidth,$MaximumHeight) {

// find image tags
preg_match_all('/<img[^>]+>/i',$HTMLContent, $rawimagearray,PREG_SET_ORDER); 

// put image tags in a simpler array
$imagearray = array();
for ($i = 0; $i < count($rawimagearray); $i++) {
    array_push($imagearray, $rawimagearray[$i][0]);
}

// put image attributes in another array
$imageinfo = array();
foreach($imagearray as $img_tag) {

    preg_match_all('/(src|width|height)=("[^"]*")/i',$img_tag, $imageinfo[$img_tag]);
}

// combine everything into one array
$AllImageInfo = array();
foreach($imagearray as $img_tag) {

    $ImageSource = str_replace('"', '', $imageinfo[$img_tag][2][0]);
    $OrignialWidth = str_replace('"', '', $imageinfo[$img_tag][2][1]);
    $OrignialHeight = str_replace('"', '', $imageinfo[$img_tag][2][2]);

    $NewWidth = $OrignialWidth; 
    $NewHeight = $OrignialHeight;
    $AdjustDimensions = "F";

    if($OrignialWidth > $MaximumWidth) { 
        $diff = $OrignialWidth-$MaximumHeight; 
        $percnt_reduced = (($diff/$OrignialWidth)*100); 
        $NewHeight = floor($OrignialHeight-(($percnt_reduced*$OrignialHeight)/100)); 
        $NewWidth = floor($OrignialWidth-$diff); 
        $AdjustDimensions = "T";
    }

    if($OrignialHeight > $MaximumHeight) { 
        $diff = $OrignialHeight-$MaximumWidth; 
        $percnt_reduced = (($diff/$OrignialHeight)*100); 
        $NewWidth = floor($OrignialWidth-(($percnt_reduced*$OrignialWidth)/100)); 
        $NewHeight= floor($OrignialHeight-$diff); 
        $AdjustDimensions = "T";
    } 

    $thisImageInfo = array('OriginalImageTag' => $img_tag , 'ImageSource' => $ImageSource , 'OrignialWidth' => $OrignialWidth , 'OrignialHeight' => $OrignialHeight , 'NewWidth' => $NewWidth , 'NewHeight' => $NewHeight, 'AdjustDimensions' => $AdjustDimensions);
    array_push($AllImageInfo, $thisImageInfo);
}

// build array of before and after tags
$ImageBeforeAndAfter = array();
for ($i = 0; $i < count($AllImageInfo); $i++) {

    if($AllImageInfo[$i]['AdjustDimensions'] == "T") {
        $NewImageTag = str_ireplace('width="' . $AllImageInfo[$i]['OrignialWidth'] . '"', 'width="' . $AllImageInfo[$i]['NewWidth'] . '"', $AllImageInfo[$i]['OriginalImageTag']);
        $NewImageTag = str_ireplace('height="' . $AllImageInfo[$i]['OrignialHeight'] . '"', 'height="' . $AllImageInfo[$i]['NewHeight'] . '"', $NewImageTag);

        $thisImageBeforeAndAfter = array('OriginalImageTag' => $AllImageInfo[$i]['OriginalImageTag'] , 'NewImageTag' => $NewImageTag);
        array_push($ImageBeforeAndAfter, $thisImageBeforeAndAfter);
    }
}

// execute search and replace
for ($i = 0; $i < count($ImageBeforeAndAfter); $i++) {
    $HTMLContent = str_ireplace($ImageBeforeAndAfter[$i]['OriginalImageTag'],$ImageBeforeAndAfter[$i]['NewImageTag'], $HTMLContent);
}

return $HTMLContent;

}

Voici LA solution, en PHP:

Téléchargez simplement QueryPath, puis procédez comme suit:

$doc= qp($myHtmlDoc);

foreach($doc->xpath('//img') as $img) {

   $src= $img->attr('src');
   $title= $img->attr('title');
   $alt= $img->attr('alt');

}

Voilà, vous avez terminé!

J'ai lu les nombreux commentaires sur cette page qui se plaignent du fait que l'utilisation d'un analyseur dom est une surcharge inutile. Cela coûte peut-être plus cher qu'un simple appel regex, mais le PO a déclaré qu'il n'y avait aucun contrôle sur l'ordre des attributs dans les balises img. Ce fait conduit à une convolution inutile du motif regex. De plus, l’utilisation d’un analyseur dom offre les avantages supplémentaires que sont la lisibilité, la maintenabilité et la connaissance de dom (regex n’est pas sensible à dom).

J'aime regex et je réponds à beaucoup de questions sur les regex, mais quand on traite avec du HTML valide, il y a rarement une bonne raison de regex avec un analyseur.

Dans la démonstration ci-dessous, observez la simplicité et la propreté de DOMDocument pour gérer les attributs de balises img dans n’importe quel ordre, avec une combinaison de guillemets (et pas de guillemets du tout). Notez également que les balises sans attribut ciblé ne perturbent pas du tout - une chaîne vide est fournie en tant que valeur.

Code: ( démo )

$test = <<<HTML
<img src="/image/fluffybunny.jpg" title="Harvey the bunny" alt="a cute little fluffy bunny" />
<img src='/image/pricklycactus.jpg' title='Roger the cactus' alt='a big green prickly cactus' />
<p>This is irrelevant text.</p>
<img alt="an annoying white cockatoo" title="Polly the cockatoo" src="/image/noisycockatoo.jpg">
<img title=something src=somethingelse>
HTML;

libxml_use_internal_errors(true);  // silences/forgives complaints from the parser (remove to see what is generated)
$dom = new DOMDocument();
$dom->loadHTML($test);
foreach ($dom->getElementsByTagName('img') as $i => $img) {
    echo "IMG#{$i}:\n";
    echo "\tsrc = " , $img->getAttribute('src') , "\n";
    echo "\ttitle = " , $img->getAttribute('title') , "\n";
    echo "\talt = " , $img->getAttribute('alt') , "\n";
    echo "---\n";
}

Sortie:

IMG#0:
    src = /image/fluffybunny.jpg
    title = Harvey the bunny
    alt = a cute little fluffy bunny
---
IMG#1:
    src = /image/pricklycactus.jpg
    title = Roger the cactus
    alt = a big green prickly cactus
---
IMG#2:
    src = /image/noisycockatoo.jpg
    title = Polly the cockatoo
    alt = an annoying white cockatoo
---
IMG#3:
    src = somethingelse
    title = something
    alt = 
---

L'utilisation de cette technique dans le code professionnel vous laissera un script propre, moins de problèmes et plus de collègues qui souhaiteraient que vous travailliez ailleurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top