像往常一样,解析 HTML 最可靠的方法是使用 DOM 解析器,而不是字符串操作。这是相当复杂的,但在遇到奇怪的情况时不会失败。
$content = "
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
<img class='bild' src='https://berlin.link/' alt='Bild von Berlin' width='300' height='200' />
Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet, vulputate, arcu.
Berlin
";
$search = "Berlin";
$replace_href = "//Berlin.test/";
$dom = new DomDocument();
libxml_use_internal_errors(true);
$dom->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DomXPath($dom);
// here we search for every text node with the search term in it
$nodes = $xpath->query("//text()[contains(., \"$search\")]");
foreach ($nodes as $node) {
// explode the string at the search term to get an array
$parts = explode($search, $node->nodeValue);
// treat the first one differently because it comes before any matches
$part1 = $dom->createTextNode(array_shift($parts));
$node->parentNode->insertBefore($part1, $node);
// now go through the rest of the string parts
foreach ($parts as $part) {
// create the a element, set the attribute value and text content
$anchor = $dom->createElement("a");
$anchor->setAttribute("href", $replace_href);
$anchor->appendChild($dom->createTextNode($search));
// append it in place
$node->parentNode->insertBefore($anchor, $node);
// and then put the original text back
$node->parentNode->insertBefore($dom->createTextNode($part), $node);
}
// get rid of the original text node
$node->parentNode->removeChild($node);
}
echo $dom->saveHTML();
输出:
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
<img class="bild" src="https://berlin.link/" alt="Bild von Berlin" width="300" height="200">
Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet, vulputate, arcu.
<a href="//Berlin.test/">Berlin</a>
</p>