Pregunta

Me gustaría crear una página donde todas las imágenes que se encuentran en mi sitio web estén enumeradas con título y representación alternativa.

Ya escribí un pequeño programa para buscar y cargar todos los archivos HTML, pero ahora no sé cómo extraerlos. src, title y alt de este HTML:

<img src="/image/fluffybunny.jpg" título="Harvey the bunny" alternativo="a cute little fluffy bunny" />

Supongo que esto debería hacerse con alguna expresión regular, pero dado que el orden de las etiquetas puede variar y las necesito todas, realmente no sé cómo analizar esto de una manera elegante (podría hacerlo con el carácter duro manera char, pero eso es doloroso).

¿Fue útil?

Solución

EDITAR: ahora que sé mejor

Usar regexp para resolver este tipo de problema es una mala idea y probablemente conducirá a un código poco confiable y que no se pueda mantener. Mejor utilice un analizador de HTML .

Solución con regexp

En ese caso, es mejor dividir el proceso en dos partes:

  • obtener toda la etiqueta img
  • extraer sus metadatos

Asumiré que su documento no es estricto con xHTML, por lo que no puede usar un analizador XML. P.EJ. con el código fuente de esta página 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)" />

[...]
        )

)

Luego obtenemos todos los atributos de la etiqueta img con un bucle:

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

        )

   [..]
        )

)

Las expresiones regulares son intensivas en CPU, por lo que es posible que desee almacenar en caché esta página. Si no tiene un sistema de caché, puede modificar el suyo usando ob_start y cargar / guardar desde un archivo de texto.

¿Cómo funciona esto?

Primero, usamos preg_ match_ all , una función que hace que cada cadena coincida con el patrón y la supera en su tercer parámetro.

Las expresiones regulares:

<img[^>]+>

Lo aplicamos en todas las páginas web html. Se puede leer como cada cadena que comienza con & Quot; <img & Quot ;, contiene non & Quot; & Gt; & Quot; char y termina con > .

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

Lo aplicamos sucesivamente en cada etiqueta img. Se puede leer como cada cadena que comienza con & Quot; alt & Quot ;, & Quot; title & Quot; o " src " ;, luego un " = " ;, luego un '" ', un montón de cosas que no son' " 'y termina con un' " '. Aísle las subcadenas entre () .

Finalmente, cada vez que quiera lidiar con expresiones regulares, es útil tener buenas herramientas para probarlas rápidamente. Verifique este probador de expresiones regulares en línea .

EDITAR: responde al primer comentario.

Es cierto que no pensé en las (con suerte pocas) personas que usan comillas simples.

Bueno, si usa solo ', simplemente reemplace todos los " por '.

Si mezclas ambos. Primero debe abofetearse :-), luego intente usar (& Quot; | ') en su lugar o & Quot; y [^ & # 248;] para reemplazar [^ "].

Otros consejos

$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 para dar un pequeño ejemplo del uso de la funcionalidad XML de PHP para la tarea:

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

Utilicé el método DOMDocument::loadHTML() porque este método puede hacer frente a la sintaxis HTML y no obliga al documento de entrada a ser XHTML. Estrictamente hablando, la conversión a un SimpleXMLElement no es necesaria, solo hace que usar xpath y los resultados de xpath sean más simples.

Si es XHTML, su ejemplo es que solo necesita 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);
?>

Salida:

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

El script debe editarse así

foreach( $result[0] as $img_tag)

porque preg_match_all devuelve una matriz de matrices

Puede usar simplehtmldom . La mayoría de los selectores jQuery son compatibles con simplehtmldom. A continuación se muestra un ejemplo

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

Utilicé preg_match para hacerlo.

En mi caso, tenía una cadena que contenía exactamente una etiqueta <img> (y ninguna otra marca) que obtuve de Wordpress e intentaba obtener el atributo src para poder ejecutarlo a través de 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);

En el patrón para tomar el título o la alt, simplemente puede usar $pattern = '/title="([^"]*)"/'; para tomar el título o <=> para tomar la alt. Lamentablemente, mi expresión regular no es lo suficientemente buena como para tomar los tres (alt / title / src) con una sola pasada.

Aquí hay una función PHP que colaboré con toda la información anterior para un propósito similar, es decir, ajustar las propiedades de ancho y largo de la etiqueta de la imagen sobre la marcha ... quizás un poco torpe, pero parece funcionar de manera confiable:

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;

}

Aquí está LA solución, en PHP:

Simplemente descargue QueryPath y luego haga lo siguiente:

$doc= qp($myHtmlDoc);

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

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

}

¡Eso es, ya terminaste!

He leído los muchos comentarios en esta página que se quejan de que el uso de un analizador dom es una sobrecarga innecesaria. Bueno, puede ser más costoso que una simple llamada regex, pero el OP ha declarado que no hay control sobre el orden de los atributos en las etiquetas img. Este hecho conduce a una convolución de patrón de expresiones regulares innecesarias. Más allá de eso, el uso de un analizador de dom proporciona los beneficios adicionales de legibilidad, mantenibilidad y conciencia de dom (regex no es consciente de dom).

Me encanta la expresión regular y respondo muchas preguntas sobre expresiones regulares, pero cuando se trata de HTML válido, rara vez hay una buena razón para expresar sobre un analizador.

En la demostración a continuación, vea cuán fácil y limpio DOMDocument maneja los atributos de la etiqueta img en cualquier orden con una mezcla de comillas (y sin comillas). Tenga en cuenta también que las etiquetas sin un atributo específico no son perjudiciales en absoluto: se proporciona una cadena vacía como valor.

Código: ( 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";
}

Salida:

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 = 
---

El uso de esta técnica en código profesional te dejará con un script limpio, menos problemas con los que lidiar y menos colegas que deseen trabajar en otro lugar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top