Эта пара функций должна делать то, что вы хотите без проблем, которые возникают при разборе HTML с регулярным выражением или str_replace
.
function process($node, $replaceRules)
{
if($node->hasChildNodes()) {
$nodes = array();
foreach ($node->childNodes as $childNode) {
$nodes[] = $childNode;
}
foreach ($nodes as $childNode) {
if ($childNode instanceof DOMText) {
$text = preg_replace(
array_keys($replaceRules),
array_values($replaceRules),
$childNode->wholeText);
$node->replaceChild(new DOMText($text),$childNode);
}
else {
process($childNode, $replaceRules);
}
}
}
}
function addLinks($str_in, $replaces)
{
$replaceRules = array();
foreach($replaces as $k=>$v) {
$k = '/\b(' . $k . ')\b/i';
$v = '<a href="' . $v . '">$1</a>';
$replaceRules[$k] = $v;
}
$doc = new DOMDocument;
$doc->loadHTML($str_in);
process($doc->documentElement, $replaceRules);
return html_entity_decode($doc->saveHTML());
}
Примечание: Не нужно беспокоиться, если HTML плохо структурирован (как в вашем примере);однако, вывод будет хорошо структурирован.
Кредит, где он должен: Рекурсивная функция process()
, которая выполняет большую часть реальной работы, поступает прямо из ответа Лукаша Лалинского на Как заменить текст в HTML .addLinks()
- это всего лишь пример использования, адаптированный к вашему вопросу.