所以我的理解是你有一个单词列表,需要在 HTML 正文中链接。 str_replace() 处理它,但不适用于锚点内的链接?
如果匹配词在锚标签内,您希望忽略它们?
PHP 不支持可变宽度的负向回溯,因此在匹配单词之前有锚标记的地方很难说不匹配,因为头部锚标记是可变长度的。
我处理此类问题的方式是全部替换,然后撤消不应该进行的更改。
<?php
// Setup data
$words = array('lorem' => 'www.google.com',
'ipsum' => 'www.bbc.co.uk',
'test' => 'www.amazon.co.uk');
$textBody = '<p>This is a short test of <a href="www.slashdot.org">lorem ipsum</a> automatic anchoring. Let us see if it works, any incidences of lorem or ipsum, should be caught.</p>';
// Make basic replacements, but use a different tag than anchor
// so it can be detected separately from previously existing anchors
// I am using the <argh> tag
$wordExpressions = array();
$wordReplacements = array();
foreach ($words as $cWord => $cLink) {
$wordExpressions[] = '#' . preg_quote($cWord) . '#';
$wordReplacements[] = '<argh href="' . $cLink . '">' . $cWord . '</argh>';
}
$replacedText = preg_replace($wordExpressions, $wordReplacements, $textBody);
// At the moment, there are nested anchors
echo $replacedText;
// Use a fairly horrific recursive anchor tag callback replacement to delete any
// <argh> tags inside <a> tags
$replacedText =
preg_replace_callback("#(<a [^>]*>)((?:[^<]|<(?!/?a>)|(?R))+)(</a>)#",
create_function('$a', 'return $a[1] . preg_replace("#<argh[^>]*>(.*?)</argh>#", "$1", $a[2]) . $a[3];'),
$replacedText);
// No nested anchors now
echo $replacedText;
// Finally replace the <argh> tags with straight <a>s
$replacedText = preg_replace(array('#<argh #', '#</argh>#'), array('<a ', '</a>'), $replacedText);
// The output should now be correct
echo $replacedText;
?>
这看起来有点糟糕,尤其是递归正则表达式回调。所做的只是匹配成对的锚标签并将匹配传递给一个函数,该函数简单地返回修补的对并从内部内容中去除新标签。在"Mastering Regular Expressions" by Jeffery Friedl 中有一个很好的关于递归替换的讨论。
标签可以是任何东西,我使用了这个词,因为它不太可能存在于 HTML 中并且似乎适合手头的问题。 :-)
这样的事情对你有用吗?