Domanda

Vorrei creare una pagina in cui tutte le immagini che risiedono sul mio sito Web sono elencate con titolo e rappresentazione alternativa.

Ho già scritto un piccolo programma per trovare e caricare tutti i file HTML, ma ora sono bloccato su come estrarre src, title e alt da questo HTML:

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

Immagino che questo dovrebbe essere fatto con un po 'di regex, ma poiché l'ordine dei tag può variare e ho bisogno di tutti loro, non so davvero come analizzarlo in un modo elegante (potrei farlo il carattere duro a proposito, ma è doloroso).

È stato utile?

Soluzione

EDIT: ora che conosco meglio

L'uso di regexp per risolvere questo tipo di problema è una cattiva idea e probabilmente porterà a un codice non mantenibile e inaffidabile. Meglio usare un parser HTML .

Soluzione con regexp

In tal caso è meglio dividere il processo in due parti:

  • ottieni tutto il tag img
  • estrae i loro metadati

Presumo che il tuo documento non sia xHTML rigoroso, quindi non puoi usare un parser XML. PER ESEMPIO. con questo codice sorgente di questa pagina 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)" />

[...]
        )

)

Quindi otteniamo tutti gli attributi del tag img con un ciclo:

$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"
                )

        )

   [..]
        )

)

I regexps richiedono molta CPU, quindi potresti voler memorizzare questa pagina nella cache. Se non disponi di un sistema di cache, puoi modificare il tuo utilizzando ob_start e caricamento / salvataggio da un file di testo.

Come funziona questa roba?

Innanzitutto, utilizziamo preg_ match_ all , una funzione che ottiene ogni stringa corrispondente al modello e lo genera nel suo terzo parametro.

Le regexps:

<img[^>]+>

Lo applichiamo su tutte le pagine Web HTML. Può essere letto come ogni stringa che inizia con & Quot; <img & Quot ;, contiene non & Quot; & Gt; & Quot; char e termina con un > .

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

Lo applichiamo successivamente su ogni tag img. Può essere letto come ogni stringa che inizia con & Quot; alt & Quot ;, & Quot; titolo & Quot; oppure " src " ;, quindi a " = " ;, quindi a '" ', un mucchio di cose che non sono' " 'e termina con un' " '. Isolare le sottostringhe tra () .

Infine, ogni volta che vuoi affrontare regexps, è utile avere buoni strumenti per testarli rapidamente. Controlla questo tester regexp online .

EDIT: rispondi al primo commento.

È vero che non pensavo alle (speriamo poche) persone che usano virgolette singole.

Bene, se usi solo ', sostituisci semplicemente tutte le " di '.

Se mescoli entrambi. Per prima cosa dovresti schiaffeggiare :-), quindi provare a usare (& Quot; | ') invece o & Quot; e [^ & # 248;] per sostituire [^ "].

Altri suggerimenti

$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');
}

Solo per dare un piccolo esempio dell'uso della funzionalità XML di PHP per l'attività:

$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'];
}

Ho usato il metodo DOMDocument::loadHTML() perché questo metodo può far fronte alla sintassi HTML e non impone che il documento di input sia XHTML. A rigor di termini, la conversione in SimpleXMLElement non è necessaria: semplifica l'utilizzo di xpath e i risultati di xpath sono più semplici.

Se si tratta di XHTML, l'esempio è, è necessario solo simpleXML.

<?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);
?>

Output:

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"
  }
}

Lo script deve essere modificato in questo modo

foreach( $result[0] as $img_tag)

perché preg_match_all restituisce array di matrici

Puoi utilizzare simplehtmldom . La maggior parte dei selettori jQuery sono supportati in simplehtmldom. Di seguito è riportato un esempio

// 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>'; 

Ho usato preg_match per farlo.

Nel mio caso, avevo una stringa contenente esattamente un <img> tag (e nessun altro markup) che ho ricevuto da Wordpress e stavo cercando di ottenere l'attributo src in modo da poterlo eseguire attraverso 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);

Nel modello per afferrare il titolo o l'alt, puoi semplicemente usare $pattern = '/title="([^"]*)"/'; per afferrare il titolo o <=> per afferrare l'alt. Purtroppo, il mio regex non è abbastanza buono da afferrare tutti e tre (alt / title / src) con un passaggio.

Ecco una funzione PHP che ho messo insieme da tutte le informazioni di cui sopra per uno scopo simile, vale a dire regolare al volo le proprietà di larghezza e lunghezza dei tag immagine ... un po 'goffo, forse, ma sembra funzionare in modo affidabile:

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;

}

Ecco LA soluzione, in PHP:

Basta scaricare QueryPath, quindi fare come segue:

$doc= qp($myHtmlDoc);

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

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

}

Ecco fatto, hai finito!

Ho letto i molti commenti su questa pagina che lamentano che l'utilizzo di un parser dom non è necessario. Bene, può essere più costoso di una semplice chiamata regex, ma l'OP ha dichiarato che non esiste alcun controllo sull'ordine degli attributi nei tag img. Questo fatto porta a una convoluzione del pattern regex non necessaria. Inoltre, l'uso di un parser dom offre i vantaggi aggiuntivi di leggibilità, manutenibilità e consapevolezza del dom (regex non è a conoscenza del dom).

Adoro regex e rispondo a molte domande su regex, ma quando si ha a che fare con HTML valido raramente c'è una buona ragione per regex su un parser.

Nella dimostrazione di seguito, vedi come DOMDocument è semplice e pulito gestisce gli attributi dei tag img in qualsiasi ordine con una combinazione di quotazioni (e nessuna quotazione). Si noti inoltre che i tag senza un attributo target non sono affatto distruttivi: viene fornita una stringa vuota come valore.

Codice: ( Demo )

$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";
}

Output:

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'uso di questa tecnica nel codice professionale ti lascerà con uno script pulito, meno singhiozzi con cui lottare e meno colleghi che desiderano che tu abbia lavorato altrove.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top