【问题标题】:Add domain to <img> src attribute value if a relative path如果是相对路径,则将域添加到 <img> src 属性值
【发布时间】:2022-01-26 20:55:49
【问题描述】:

我有一个文本变量,其中包含多个具有相对或绝对路径的图像。我需要检查 src 属性是否以httphttps 开头,然后忽略它,但如果它以/ 或类似abc/ 开头,则添加一个基本网址。

我尝试如下:

<?php
$html = <<<HTML
<img src="docs/relative/url/img.jpg" />
<img src="/docs/relative/url/img.jpg" />
<img src="https://docs/relative/url/img.jpg" />
<img src="http://docs/relative/url/img.jpg" />
HTML;

$base = 'https://example.com/';

$pattern = "/<img src=\"[^http|https]([^\"]*)\"/";
$replace = "<img src=\"" . $base . "\${1}\"";
echo $text = preg_replace($pattern, $replace, $html);

我的输出是:

<img src="https://example.com/ocs/relative/url/img.jpg" />
<img src="https://example.com/docs/relative/url/img.jpg" />
<img src="https://docs/relative/url/img.jpg" />
<img src="http://docs/relative/url/img.jpg" />

这里的问题:我得到了 99% 的结果正确,但是当 src 属性以 docs/ 之类的东西开头时,它的第一个字母被切断了。 (请检查输出中的第一个 img src)

我需要的输出是:

<img src="https://example.com/docs/relative/url/img.jpg" /><!--check this and compare with current result, you will get the difference -->
<img src="https://example.com/docs/relative/url/img.jpg" />
<img src="https://docs/relative/url/img.jpg" />
<img src="http://docs/relative/url/img.jpg" />

谁能帮我纠正一下。

【问题讨论】:

    标签: php regex dom replace src


    【解决方案1】:

    以下模式将寻找不以httphttps 开头的src 属性。然后对于以正斜杠开头的相对路径,在将 $base 字符串添加到 src 值之前,将删除前导斜杠。

    代码:(Demo)

    $base = 'https://example.com/';
    echo preg_replace('~ src="(?!http)\K/?~', $base, $html);
    

    输出:

    <img src="https://example.com/docs/relative/url/img.jpg" />
    <img src="https://example.com/docs/relative/url/img.jpg" />
    <img src="https://docs/relative/url/img.jpg" />
    <img src="http://docs/relative/url/img.jpg" />
    

    细分:

    ~           #starting pattern delimiter
     src="      #match space, s, r, c, =, then "
    (?!http)    #only continue matching if not https or http
    \K          #forget any previously matched characters so they are not destroyed by the replacement string
    /?          #optionally match a forward slash
    ~           #ending pattern delimiter
    

    至于你的模式,/&lt;img src=\"[^http|https]([^\"]*)\"/:

    1. [^http|https] 实际上意味着“匹配一个不在此列表中的单个字符:|htps。它可以简化为 [^|hpst],因为“否定字符类”中列出的字符是无关紧要的,重复字符是没有意义的。所以你看,[^...] 不是你所说的“字符串以某事或某事开头”。
    2. 捕获子字符串中的所有剩余字符直到下一个双引号以在替换中再次使用它是不必要的。这就是为什么我使用\K 来确定应该在哪里注入$base 而不是([^\"]*)

    此外,在处理有效的 HTML 文档时,我总是推荐 DOM 解析器的稳定性。您可以使用带有 XPath 的 DOMDocument 来定位符合条件的元素并在不使用正则表达式的情况下修改 src 属性。

    代码:(Demo)

    $dom = new DOMDocument; 
    $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    $xpath = new DOMXPath($dom);
    foreach ($xpath->query("//img[not(starts-with(@src, 'http'))]") as $node) {
        $node->setAttribute('src', $base . ltrim($node->getAttribute('src'), '/'));
    }
    echo $dom->saveHTML();
    

    相关回答:https://stackoverflow.com/a/48837947/2943403

    【讨论】:

    • 谢谢哥们。你救了我。我不擅长正则表达式。请让我知道我可以从哪里开始学习正则表达式以及它的模式以便更好地理解。
    • 基本上,自从我加入 SO 并通过实践学习以来,我只是阅读了 Wiktor 的所有答案。 Regex101.com 是一个很棒的沙箱,因为它会在您创建模式时解释/分解模式。
    • 没有。只需阅读他最近的所有答案,然后随着时间的推移向后工作。他总是解释他做什么以及为什么(如何在 SO 上发布答案的一个很好的榜样)。将每个答案视为您的下一课。遍历他的模式的每一步。如果某些事情没有意义,请研究该技术。 Wiktor 也有一些 youtube 教程,但我没有看过。查看他的个人资料:stackoverflow.com/users/3832970/wiktor-stribi%c5%bcew
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 2016-07-17
    • 2015-11-14
    • 2014-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多