首先,解析与HTML解析器的文字,喜欢的东西DOMDocument::loadHTML
。请注意,糟糕的HTML可能很难解析,并且根据解析器的不同,在运行此类函数后,浏览器中的输出可能会略有不同。
PHP的DOMDocument
在这方面不是很灵活。通过与其他工具解析,您可能会有更好的运气。但是,如果你使用有效的HTML(并且你应该尝试,如果它在你的控制范围内),那么这些都不是问题。
解析文本后,您需要查看链接的文本节点并将其替换。使用正则表达式是最简单的方法。
下面是一个示例脚本,做到了这一点:
<?php
function linkify($text)
{
$re = "@\b(https?://)?(([0-9a-zA-Z_!~*'().&=+$%-]+:)?[0-9a-zA-Z_!~*'().&=+$%-]+\@)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+\.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\.[a-zA-Z]{2,6})(:[0-9]{1,4})?((/[0-9a-zA-Z_!~*'().;?:\@&=+$,%#-]+)*/?)@";
preg_match_all($re, $text, $matches, PREG_OFFSET_CAPTURE);
$matches = $matches[0];
$i = count($matches);
while ($i--)
{
$url = $matches[$i][0];
if (!preg_match('@^https?://@', $url))
$url = 'http://'.$url;
$text = substr_replace($text, '<a href="'.$url.'">'.$matches[$i][0].'</a>', $matches[$i][1], strlen($matches[$i][0]));
}
return $text;
}
$dom = new DOMDocument();
$dom->loadHTML('<b>stackoverflow.com</b> <a href="stackoverflow.com">test</a>');
$xpath = new DOMXpath($dom);
foreach ($xpath->query('//text()') as $text)
{
$frag = $dom->createDocumentFragment();
$frag->appendXML(linkify($text->nodeValue));
$text->parentNode->replaceChild($frag, $text);
}
echo $dom->saveHTML();
?>
我并没有拿出与正则表达式,我不能担保其准确性。除上述情况外,我也没有测试脚本。但是,这应该足以让你走了。
输出:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<body>
<b><a href="http://stackoverflow.com">stackoverflow.com</a></b>
<a href="stackoverflow.com">test</a>
</body>
</html>
注意saveHTML()
增加了周围的标签。如果这是一个问题,你可以用substr()
去掉它们。
是否有任何特别的原因,为什么你不喜欢使用jQuery linkify? – 2010-12-07 06:22:31
我不能在我的网站上使用jQuery linkify,因为有其他脚本(mootools)与jquery有冲突。 – alhoseany 2010-12-07 20:13:44