我不知道我是否完全正确地回答了您的问题,如果您想处理包含在src="
and"
中的所有文本序列,则可以使用以下模式:
~(\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,我敢肯定,因为您没有要求 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">
只是使用了一种不同的解析方式——替换仍然是相同的。只是为了提供两种不同的方式,它们也部分相同。