preg_replace href或src,仅当缺少协议时


preg_replace href or src only when protocol is missing

我一直在分析一个输入,它是HTML。但是,我需要能够找到所有没有协议(如http://、https://或ftp://等)的href或src属性,并且当它们没有用包含协议和域的变量替换时。

例如,我想要

<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://etc.时无法使其工作

编辑:

顺便提一下,因为我很清楚这是这个问题的"范围"的一部分,所以我想避免因为替换而使用url编码,因为我在其中一些上使用了{}之类的东西,我不希望它们包含%7B%7D之类的东西。

为什么不使用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();

本质上,您正在寻找"而非"-模式。这将是一个消极的断言:

 (?!http://)

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

或者您可以使用preg_replace_callback并在那里进行排序。


既然你说了"解析",那就有点离题了;另一种选择是phpquery或用于HTML遍历的querypath。然后你可以循环所有的链接:

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

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