Preg_replace,请多多支持?
Preg_replace, please little support?
所以我有这个 preg_replace 函数(来自其他人编写的脚本),它向所有 link 添加了一个 target="_blank"
属性。但是,当我有一个已经具有 target="_blank"
属性的 link 时,它会添加另一个。这会导致 link 中出现双 target="_blank"
属性。有没有办法在下面的 preg_replace 函数中解决这个问题?
$text = preg_replace('%(<a[^>]+)(href="https?://)((?:(?!(' . $host . '))[^"])+|(?:(?=(' . $host . '/' . $base_url . '/))[^"]+))"%i', '"target="_blank"', $text);
非常感谢!
正则表达式对于这种 html 操作来说不是好方法而且非常方便。一种首选方法是使用 DOMDocument,这是一种使用 libxml 从 HTML 文档构建节点树(DOMNode
实例)的工具。 DOMNode
class 有几个有用的方法和属性来做你想做的事,比如 hasAttribute
和 setAttribute
:
$dom = new DOMDocument;
$dom->loadHTMLFile('yourhtmlfile.html');
// or $dom->loadHTML($htmlContent); //if the html is already in a variable
// get all the link nodes
$linkNodeList = $dom->getElementsByTagName('a');
foreach($linkNodeList as $linkNode) {
if (!$linkNode->hasAttribute('target'))
$linkNode->setAttribute('target', '_blank');
}
$result = $dom->saveHTML();
注意:如果你想在 href 属性中针对特定的域和基础 url,你可以将 if
语句更改为:
if ( $linkNode->hasAttribute('target')
&& strpos($host . '/' . $baseurl, $linkNode->getAttribute('href')) !== false)
或者另一种方法是使用 XPath 查询立即定位您想要的链接:
$dom = new DOMDocument;
$dom->loadHTMLFile('yourhtmlfile.html');
$xp = new DOMXPath($dom);
$query = '//a[contains(@href, "' . $host . '/' . $baseurl . '") and not(@target)]';
$linkNodeList = $xp->query($query);
foreach ($linkNodeList as $linkNode) {
$linkNode->setAttribute('target', '_blank');
}
$result = $dom->saveHTML();
注意:如果您正在使用部分 html 文档,DOMDocument 会自动添加一个 DTD 并创建 html 和 body 标签。为防止这种情况,有几种解决方法:
使用 PHP >= 5.4 加载文档时需要添加两个选项:
$dom->loadHTMLFile('yourhtmlfile.html', LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
(有时由于未知原因常量 LIBXML_HTML_NODEFDTD
和 LIBXML_HTML_NOIMPLIED
未定义。在这种情况下,您可以将它们替换为它们的值 4
和 8192
,或者在前面定义,或者直接使用8196
即4 | 8192
)
的结果
使用 PHP >= 5.1 的方法是用 saveXML
一个一个地保存每个 body childNodes 并连接字符串:
$result = '';
$bodyChildNodes = $dom->getElementsByTagName('body')->item(0)->childNodes;
foreach ($bodyChildNodes as $childNode) {
$result .= $dom->saveXML($childNode);
}
对于较低的 PHP 版本,使用字符串方法:
$result = preg_replace('~\A.*?<body>|</body></html>\z~s', '', $result);
或
$result = explode('<body>', $result, 2);
$result = substr($result[1], 0, -14); // 14 is the string length of "</body></html>"
所以我有这个 preg_replace 函数(来自其他人编写的脚本),它向所有 link 添加了一个 target="_blank"
属性。但是,当我有一个已经具有 target="_blank"
属性的 link 时,它会添加另一个。这会导致 link 中出现双 target="_blank"
属性。有没有办法在下面的 preg_replace 函数中解决这个问题?
$text = preg_replace('%(<a[^>]+)(href="https?://)((?:(?!(' . $host . '))[^"])+|(?:(?=(' . $host . '/' . $base_url . '/))[^"]+))"%i', '"target="_blank"', $text);
非常感谢!
正则表达式对于这种 html 操作来说不是好方法而且非常方便。一种首选方法是使用 DOMDocument,这是一种使用 libxml 从 HTML 文档构建节点树(DOMNode
实例)的工具。 DOMNode
class 有几个有用的方法和属性来做你想做的事,比如 hasAttribute
和 setAttribute
:
$dom = new DOMDocument;
$dom->loadHTMLFile('yourhtmlfile.html');
// or $dom->loadHTML($htmlContent); //if the html is already in a variable
// get all the link nodes
$linkNodeList = $dom->getElementsByTagName('a');
foreach($linkNodeList as $linkNode) {
if (!$linkNode->hasAttribute('target'))
$linkNode->setAttribute('target', '_blank');
}
$result = $dom->saveHTML();
注意:如果你想在 href 属性中针对特定的域和基础 url,你可以将 if
语句更改为:
if ( $linkNode->hasAttribute('target')
&& strpos($host . '/' . $baseurl, $linkNode->getAttribute('href')) !== false)
或者另一种方法是使用 XPath 查询立即定位您想要的链接:
$dom = new DOMDocument;
$dom->loadHTMLFile('yourhtmlfile.html');
$xp = new DOMXPath($dom);
$query = '//a[contains(@href, "' . $host . '/' . $baseurl . '") and not(@target)]';
$linkNodeList = $xp->query($query);
foreach ($linkNodeList as $linkNode) {
$linkNode->setAttribute('target', '_blank');
}
$result = $dom->saveHTML();
注意:如果您正在使用部分 html 文档,DOMDocument 会自动添加一个 DTD 并创建 html 和 body 标签。为防止这种情况,有几种解决方法:
使用 PHP >= 5.4 加载文档时需要添加两个选项:
$dom->loadHTMLFile('yourhtmlfile.html', LIBXML_HTML_NODEFDTD | LIBXML_HTML_NOIMPLIED);
(有时由于未知原因常量 LIBXML_HTML_NODEFDTD
和 LIBXML_HTML_NOIMPLIED
未定义。在这种情况下,您可以将它们替换为它们的值 4
和 8192
,或者在前面定义,或者直接使用8196
即4 | 8192
)
使用 PHP >= 5.1 的方法是用 saveXML
一个一个地保存每个 body childNodes 并连接字符串:
$result = '';
$bodyChildNodes = $dom->getElementsByTagName('body')->item(0)->childNodes;
foreach ($bodyChildNodes as $childNode) {
$result .= $dom->saveXML($childNode);
}
对于较低的 PHP 版本,使用字符串方法:
$result = preg_replace('~\A.*?<body>|</body></html>\z~s', '', $result);
或
$result = explode('<body>', $result, 2);
$result = substr($result[1], 0, -14); // 14 is the string length of "</body></html>"