【问题标题】:preg_replace href or src only when protocol is missing仅当缺少协议时 preg_replace href 或 src
【发布时间】:2012-02-02 00:48:29
【问题描述】:

我正在解析一个输入,即 HTML。但是,我需要能够找到所有没有协议的 href 或 src 属性,例如 http://、https:// 或 ftp:// 等,并且当它们没有将其替换为一个包含协议和域的变量。

比如说我想要

<a href="/_mylink/goes/here">Link 1</a>
<a href="http://site.com/_myotherlink/goes/here">Link 2</a>

返回:

<a href="http://mydomain.com/_mylink/goes/here">Link 1</a>
<a href="http://site.com/_myotherlink/goes/here">Link 2</a>

我可以获得整个 href 属性,但我似乎无法弄清楚如何仅在缺少协议时匹配和替换。我发现 [^0-9] 会以相反/非方式工作,但我发现在尝试使用 http:// 等时我无法让它工作。

编辑:

只是提一下,因为对我来说很明显它是这个问题的“范围”的一部分,我想避免由于替换而使用 url 编码,因为我使用 {} 之类的东西其中一些,我不希望它们中有 %7B %7D 之类的东西。

【问题讨论】:

    标签: php regex preg-replace


    【解决方案1】:

    为什么不使用 DOM 轻松替换这些属性呢?例如

    $domain = 'http://mydomain.com';
    $currentPath = '/some/absolute/path/'; // make sure this starts and ends with a forward-slash
    
    $doc = new DOMDocument();
    $doc->loadHTML($html);
    
    $xpath = new DOMXPath($doc);
    $attrs = $xpath->query('//@href[not(contains(., "://"))]');
    foreach ($attrs as $attr) {
        $attr->value = sprintf('%s%s%s',
            $domain,
            $attr->value[0] == '/' ? '' : $currentPath,
            htmlspecialchars($attr->value)
        );
    }
    
    $attrs = $xpath->query('//@src[not(contains(., "://"))]');
    foreach ($attrs as $attr) {
        $attr->value = sprintf('%s%s%s',
            $domain,
            $attr->value[0] == '/' ? '' : $currentPath,
            htmlspecialchars($attr->value)
        );
    }
    
    echo $doc->saveHTML();
    

    【讨论】:

    • 我正在编写一个类似的解决方案,它使用 $doc->getElementsByTagName("a") 代替,然后使用 strpos() 过滤掉以“/”开头的 href。我喜欢您的解决方案如何与 xpath 一起完成这两项任务。 +1,很好。
    • 这会导致问题,因为它似乎会自动 urlencode() 属性,这是我希望在该代码点避免的功能。有没有办法关闭它?
    • @ScottFlack 这可能是由于saveHTML()。请改用saveXML()。此外,我已将 htmlspecialchars() 添加到属性值分配中,因为您似乎需要在 PHP 中执行此操作
    • @Phil 谢谢,这似乎使这个解决方案现在可以满足我的需求。欣赏它。
    【解决方案2】:

    本质上,您正在寻找“not”模式。那将是negative assertion:

     (?!http://)
    

    例如在/href="(?!http://)[^"]+"/ 中添加。

    或者您可以使用preg_replace_callback 并在那里进行整理。


    既然你说的是“解析”,那就有点话题了;对于 HTML 遍历,替代方案是 。然后你可以遍历所有链接:

     foreach (htmlqp($html)->find("a[href]") as $tag) {
          if (!strstr($tag->attr("href"), "http://")) {
                 $tag->attr("href", "$add....");
    

    显然对于输出转换来说太过分了。但对于任意 HTML 来说可能是一个更有弹性的选择。

    【讨论】:

    • 我真的很喜欢这看起来多么简单和简短,但由于某种原因我无法让它工作,尽管我认为这更多地与我有关而不是实际答案,因为我可以得到它可以在周围的在线“测试正则表达式”系统之一中工作,但不能在我的实际站点代码中工作。
    • 非常感谢,因为 (?!) 现在在我的代码的其他地方也派上了用场,非常感谢!
    猜你喜欢
    • 2020-02-24
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-05
    相关资源
    最近更新 更多