【问题标题】:Regular expression to replace an <a> with respective <img>用相应的 <img> 替换 <a> 的正则表达式
【发布时间】:2010-11-29 19:16:19
【问题描述】:

我正在寻找一个 PHP preg_replace() 解决方案找到图像的链接并将它们替换为相应的图像标签。

查找:

<a href="http://www.domain.tld/any/valid/path/to/imagefile.ext">This will be ignored.</a>

替换为:

<img src="http://www.domain.tld/any/valid/path/to/imagefile.ext" alt="imagefile" />

如果协议必须是 http://,.ext 必须是有效的图像格式(.jpg、.jpeg、.gif、.png、.tif),并且基本文件名变为 alt=""价值。

我知道 preg_replace() 是适合这项工作的函数,但我很喜欢正则表达式,所以非常感谢任何帮助!谢谢!

【问题讨论】:

    标签: php regex preg-replace


    【解决方案1】:

    我建议使用这个更灵活的非 greddy 正则表达式:

    <a[^>]+?href=\"(http:\/\/[^\"]+?\/([^\"]*?)\.(jpg|jpeg|png|gif))[^>]*?>[^<]*?<\/a>
    

    还有一个更复杂的正则表达式(包括 PHP 测试代码),希望能取悦 Gumbo :)

    <?php
    $test_data = <<<END
    <a blabla="asldlsaj" alksjada="aslkdj" href="http://www.domain.tld/any/valid/path/to/imagefile.jpg" lkjasd=""asdlaskjd>This will be ignored.</a>
    Lorem ipsum..
    <a    blabla=asldlsaj alksjada="aslkdj" href="http://www.domain.tld/any/valid/path/to/imagefile.jpg" lkjasd=""asdlaskjd>This will be ignored.</a>
    <a lkjafs='asdsa> ' blabla="asldlksjada=>"aslkdj" href="http://www.domain.tld/any/valid/path/to/imagefile.jpg" lkjasd=""asdlaskjd>This will be ignored.</a>
    <a    blabla="ajada="aslk href="http://www.domain.tld/any/valid/path>/to/imagefile.jpg" lkjasd>asdlaskjd>This will be ignored.</a>
    <a    blabla="asldlsaj>" aslkdj href="http://www.domain.tld/any/valid/path/ to/imagefile.jpg" lkjasd=""asdlaskjd>This will be ignored.</a>
    Something:
    <a    blabla='asldls<ajslkdj' href="http://www.domain.tld/any/valid'/path/to/imagefile.jpg" lkjasd=""asdlaskjd>This will be ignored.</a>
    <a    blabla=  asldlsadj href="http://www.domain.tld/any/valid/path/to/imagefile.jpg" lkjasd>This will be ignored.</a>
    <a blabla="asldlsaj" alksjslkdj" href='http://www.domain.tld/any/valid/path/to/imagefile.jpg' lkjasdskjd>This will be ignored.</a>
    Something else...
    <a    blabla="asldlsaj" alksjslkdj" href='http://www.domain.tld/any/valid/path/to/imagefile.jpg' lkjasdskjd>This will be ignored.</a>
    <a    blabla="asldlsaj" alksjada="aslkdj" href=http://www.domain.tld/any/valid/path/to/imagefile.jpg lkjdlaskjdll> be ignored.</a>
    END;
    $regex = "/<a\s(\s*\w+(\s*=\s*(\".*?\"|'.*?'|[^'\">\s]+))?)+?\s+href\s*=\s*(\"(http:\/\/[^\"]+\/(.*?)\.(jpg|jpeg|png|gif))\"|'(http:\/\/[^']+\/(.*?)\.(jpg|jpeg|png|gif))'|(http:\/\/[^'\">\s]+\/([^'\">\s]+)\.(jpg|jpeg|png|gif)))\s(\s*\w+(\s*=\s*(\".*?\"|'.*?'|[^'\">\s]+))?)+>[^<]*?<\/a>/i";
    $replaced = preg_replace($regex, '<img src="$5$8$11" alt="$6$9$12" />', $test_data);
    
    echo '<pre>'.htmlentities($replaced);
    ?>
    

    【讨论】:

    • 属性值允许包含文字&gt;
    【解决方案2】:

    恭喜,您是第 100 万位询问 Stack Overflow 如何使用正则表达式解析 HTML 的客户!

    [X][HT]ML 不是常规语言,不能用正则表达式可靠地解析。使用 HTML 解析器。 PHP 本身为您提供DOMDocument,或者您可能更喜欢simplehtmldom

    顺便说一句,您无法通过查看文件的 URL 来判断文件的类型。 JPEG 没有理由必须将“.jpeg”作为其扩展名 — 事实上,不能保证具有“.jpeg”扩展名的文件实际上是 JPEG。唯一可以确定的方法是获取资源(例如,使用 HEAD 请求)并查看 Content-Type 标头。

    【讨论】:

    • -1 这并不能解决问题;并且没有人关心使用正则表达式解析 HTML - 如果您是验证图像和创建标记的人,那么您可以相当确定一切都会正常工作。
    • 确实如此。然而,提问者并没有说明标记的格式在他们的控制之下。
    • 他也没有说不是。您对上下文一无所知,因此这不应该是答案,而是对问题的评论。
    • 格式化的标记在我的控制之下。这个答案几乎是无关紧要的。
    【解决方案3】:

    啊,我每天的 DOM 练习。您应该使用 DOM 来解析 HTML,并使用正则表达式来解析字符串,例如 html 属性。

    注意:我有一些基本的正则表达式肯定可以被一些向导改进:)

    注意 #2:虽然它可能会产生额外的开销,但您可以使用 curl 之类的东西通过发送 HEAD 请求并查看 Content-Type 来彻底检查 href 是否是实际图像,但这适用于 80-90病例百分比。

    <?php
    
    $content = '
    
    <a href="http://www.domain.tld/any/valid/path/to/imagefile.ext">This will be ignored.</a>
    <br>
    
    <a href="http://col.stb.s-msn.com/i/43/A4711309495C88F8CD154C99FCE.jpg">this will not be ignored</a>
    
    <br>
    
    <a href="http://col.stb.s-msn.com/i/A0/8E9A454F701E4F5F89E58E14B532C.jpg">bah</a>
    ';
    
    $dom = new DOMDocument();
    $dom->loadHTML($content);
    
    $anchors = $dom->getElementsByTagName('a');
    
    $i = $anchors->length-1;
    
    $protocol = '/^http:\/\//';
    $ext = '/([\w+]+)\.(?:gif|jpg|jpeg|png)$/';
    
    if ( count($anchors->length) > 0 ) {
        while( $i > -1 ) {
        $anchor = $anchors->item($i);
        if ( $anchor->hasAttribute('href') ) {
            $link = $anchor->getAttribute('href');
    
            if ( 
            preg_match ( $protocol , $link ) &&
            preg_match ( $ext, $link )
            ) {
            //echo 'replacing this one.';
            $image = $dom->createElement('img');
    
            if ( preg_match( $ext, $link, $matches ) ) {
                if ( count($matches) ) {
                $altName = $matches[1];
                $image->setAttribute('alt', $altName);
                }
                $image->setAttribute('src', $link);
                $anchor->parentNode->replaceChild( $image, $anchor );
            }
            }
    
        }
        $i--;
        }
    }
    
    echo $dom->saveHTML();
    

    【讨论】:

    • 太长了...这可以通过 preg_replace 来完成。看我的回答。
    • 正则表达式解决方案太容易失败,我会坚持使用 DOM 但谢谢。
    • 另外,DOM 解决方案更加灵活,因为您可以执行任何您想要的 DOM 操作,您只能使用正则表达式替换。
    猜你喜欢
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    相关资源
    最近更新 更多