Pergunta

Eu gostaria de criar uma página onde todas as imagens que residem no meu site são listados com título e representação alternativa.

Eu já me escreveu um pequeno programa para encontrar e carregar todos os arquivos HTML, mas agora eu estou preso em como extrair src, title e alt desta HTML:

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

Eu acho que isso deve ser feito com alguns regex, mas desde que a ordem das marcas pode variar, e eu preciso de todos eles, eu realmente não sei como analisar isso em uma maneira elegante (eu poderia fazê-lo da carvão duro por meio char, mas isso é doloroso).

Foi útil?

Solução

EDIT: agora que eu sei melhor

Usando regexp para resolver este tipo de problema é uma má idéia e provavelmente levará em código insustentável e não confiável. Melhor usar um HTML parser .

Solução Com regexp

Nesse caso, é melhor dividir o processo em duas partes:

  • obter toda a tag img
  • extrair seus metadados

Vou assumir o seu doc ??não xHTML é rigorosa para que você não pode usar um parser XML. POR EXEMPLO. com este código fonte da 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)" />

[...]
        )

)

Então, temos todos os atributos da marca IMG com um loop:

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

        )

   [..]
        )

)

Regexps são intensivo da CPU para que você pode querer armazenar em cache desta página. Se você não tem nenhum sistema de cache, você pode ajustar o seu próprio usando ob_start e carregamento / salvar a partir de um arquivo de texto.

Como funciona essa coisa?

Primeiro, usamos preg_ match_ todos , uma função que recebe cada corda correspondente ao padrão e ouput que nele do terceiro parâmetro.

Os regexps:

<img[^>]+>

Nós aplicá-lo em todas as páginas web HTML. Ele pode ser lido como cada cadeia que começa com "<img", contém caractere non ">" e termina com a> .

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

Nós aplicá-la sucessivamente em cada tag img. Ele pode ser lido como todas as cordas começando com "alt", "título" ou "src", então a "=", em seguida, um ' "', um monte de coisas que não são '"' e termina com uma '"'. isolar os sub-strings entre () .

Finalmente, cada vez que você quer lidar com regexps, é útil ter ferramentas boas para testá-los rapidamente. Marque esta on-line regexp tester .

EDIT:. Resposta à primeira comentário

É verdade que eu não pensar sobre as (espero que poucas) pessoas usando aspas simples.

Bem, se você usar apenas', basta substituir todos os "por'.

Se você misturar os dois. Primeiro você deve tapa-se :-), em seguida, tentar usar ( "|") em vez ou "e [^ ø] para substituir [^"]

Outras dicas

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

Apenas para dar um pequeno exemplo de como usar a funcionalidade XML do PHP para a tarefa:

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

Eu uso o método DOMDocument::loadHTML() porque este método pode lidar com HTML-sintaxe e não força o documento de entrada para ser XHTML. Estritamente falando, a conversão para um SimpleXMLElement não é necessário -. Ele só faz utilizando XPath e os resultados XPath mais simples

Se é XHTML, seu exemplo é, você só precisa 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"
  }
}

O script deve ser editado como este

foreach( $result[0] as $img_tag)

porque variedade preg_match_all retorno de matrizes

Você pode usar simplehtmldom . A maioria dos seletores jQuery são suportados no simplehtmldom. Um exemplo é dado abaixo

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

Eu costumava preg_match para fazê-lo.

No meu caso, eu tinha uma string contendo exatamente um tag <img> (e nenhum outro markup) que eu tenho de Wordpress e eu estava tentando obter o atributo src para que eu pudesse executá-lo através 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);

No padrão para agarrar o título ou o alt, você poderia simplesmente usar $pattern = '/title="([^"]*)"/'; para agarrar o título ou $pattern = '/title="([^"]*)"/'; para agarrar a alt. Infelizmente, a minha regex não é bom o suficiente para pegar todos os três (alt / título / src) com uma passagem embora.

Aqui está um PHP Função I mancando junto de todas as informações acima para um propósito semelhante, ou seja, ajustando tag imagem largura e comprimento propriedades na mosca ... um desajeitado pouco, talvez, mas parece funcionar de forma confiável:

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;

}

Aqui está a solução, em PHP:

Basta fazer o download QueryPath, e, em seguida, faça o seguinte:

$doc= qp($myHtmlDoc);

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

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

}

É isso aí, você está feito!

Eu li muitos comentários sobre esta página que se queixam de que o uso de um analisador dom é uma sobrecarga desnecessária. Bem, pode ser mais caro do que uma mera chamada regex, mas o OP tem afirmado que não há controle sobre a ordem dos atributos nas tags img. Este facto leva a desnecessária convolução padrão regex. Além disso, usando um analisador dom fornece os benefícios adicionais de leitura, manutenção e dom-consciência (regex não é dom-aware).

Eu amo regex e eu responder muitas perguntas regex, mas quando se lida com HTML válida raramente há uma boa razão para regex ao longo de um analisador.

Na demonstração abaixo, veja como atributos fácil e limpa DOMDocument alças img tag em qualquer ordem com uma mistura de citar (e não citando em tudo). Observe também que as etiquetas sem um atributo alvo não são perturbadores em tudo -. Uma cadeia vazia é fornecido como um valor

Código: ( Demonstração )

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

Usando esta técnica no código profissional vai deixar você com um script limpo, menos soluços de enfrentar, e menos colegas que desejam você trabalhou em outro lugar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top