我不确定我是否完全理解了你的问题,如果你想处理所有被src="
和"
包含的文本序列,下面的模式可以实现:
~(\ssrc=")([^"]+)(")~
这段代码包含三个捕获组,其中第二个包含您感兴趣的数据。第一个和最后一个有用于更改整个匹配项。
现在,您可以使用回调函数替换所有实例并更改位置。我已经创建了一个简单的字符串,其中包含您拥有的所有6种情况:
$site = <<<BUFFER
1. src="//www.stackoverflow.com/cat.png"
2. src="http://www.stackoverflow.com/cat.png"
3. src="https://www.stackoverflow.com/cat.png"
4. src="somedirectory/cat.png"
5. src="/cat.png"
6. src="cat.png"
BUFFER
暂且不考虑周围的HTML标签,反正你也没有要求解析HTML而是要求使用正则表达式。在下面的例子中,中间匹配的内容(即URL)将被包含以便清楚地显示它已经匹配:
现在,为了替换每个链接,让我们从轻松的角度开始,只需在字符串中突出显示它们。
$pattern = '~(\ssrc=")([^"]+)(")~';
echo preg_replace_callback($pattern, function ($matches) {
return $matches[1] . ">>>" . $matches[2] . "<<<" . $matches[3];
}, $site);
给定示例的输出如下:
1. src=">>>//www.stackoverflow.com/cat.png<<<"
2. src=">>>http://www.stackoverflow.com/cat.png<<<"
3. src=">>>https://www.stackoverflow.com/cat.png<<<"
4. src=">>>somedirectory/cat.png<<<"
5. src=">>>/cat.png<<<"
6. src=">>>cat.png<<<"
由于替换字符串的方式将被更改,因此可以进行提取,这样更容易进行更改:
$callback = function($method) {
return function ($matches) use ($method) {
return $matches[1] . $method($matches[2]) . $matches[3];
};
};
这个函数根据您传递的替换方法创建替换回调函数。
这样的替换函数可能是:
$highlight = function($string) {
return ">>>$string<<<";
};
它被称为以下内容:
$pattern = '~(\ssrc=")([^"]+)(")~';
echo preg_replace_callback($pattern, $callback($highlight), $site);
输出结果不变,这只是为了说明提取的工作原理:
1. src=">>>//www.stackoverflow.com/cat.png<<<"
2. src=">>>http://www.stackoverflow.com/cat.png<<<"
3. src=">>>https://www.stackoverflow.com/cat.png<<<"
4. src=">>>somedirectory/cat.png<<<"
5. src=">>>/cat.png<<<"
6. src=">>>cat.png<<<"
这样做的好处在于替换函数只需要处理URL匹配为单个字符串,而不是针对不同组的正则表达式匹配数组。
现在回答你问题的后半部分:如何用特定的URL处理方式来替换它,比如删除文件名。可以通过解析URL并从路径组件中删除文件名(基名)来完成此操作。由于提取作用,您可以将其放入一个简单的函数中:
$removeFilename = function ($url) {
$url = new Net_URL2($url);
$base = basename($path = $url->getPath());
$url->setPath(substr($path, 0, -strlen($base)));
return $url;
};
这段代码使用了
Pear的Net_URL2 URL组件(也可通过Packagist和Github获取,您的操作系统包可能也有它)。它可以轻松解析和修改URL,因此在工作中很有用。
现在,使用新的URL文件名替换函数完成替换:
$pattern = '~(\ssrc=")([^"]+)(")~';
echo preg_replace_callback($pattern, $callback($removeFilename), $site);
并且结果如下:
1. src="//www.stackoverflow.com/"
2. src="http://www.stackoverflow.com/"
3. src="https://www.stackoverflow.com/"
4. src="somedirectory/"
5. src="/"
6. src=""
请注意,这只是一个示例。它展示了如何使用正则表达式实现此操作。但您也可以使用HTML解析器来执行此操作。让我们将其制作成一个实际的HTML片段:
1. <img src="//www.stackoverflow.com/cat.png"/>
2. <img src="http://www.stackoverflow.com/cat.png"/>
3. <img src="https://www.stackoverflow.com/cat.png"/>
4. <img src="somedirectory/cat.png"/>
5. <img src="/cat.png"/>
6. <img src="cat.png"/>
接下来,使用创建的替换过滤函数处理所有<img>
标签的"src
"属性:
$doc = new DOMDocument();
$saved = libxml_use_internal_errors(true);
$doc->loadHTML($site, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_use_internal_errors($saved);
$srcs = (new DOMXPath($doc))->query('//img/@hsrc') ?: [];
foreach ($srcs as $src) {
$src->nodeValue = $removeFilename($src->nodeValue);
}
echo $doc->saveHTML();
结果再次是:
1. <img src="//www.stackoverflow.com/cat.png">
2. <img src="http://www.stackoverflow.com/cat.png">
3. <img src="https://www.stackoverflow.com/cat.png">
4. <img src="somedirectory/cat.png">
5. <img src="/cat.png">
6. <img src="cat.png">
使用了不同的解析方式,但替换仍然相同。只是提供两种部分相同的不同方式。
str_replace('</head>', '<base href="http://www.stackoverflow.com"></head>',$site )
的操作。 - zen