如果@daftcoder 的解决方案对您有用,那很好,但如果您的代码中有实体(< 等),它确实会失败。我找不到任何其他失败的案例。
如果这很重要,您可以在 PHP 中使用 DOM 操作。我知道这要复杂得多,但它应该比简单的正则表达式在更多情况下工作。
walk 和 doReplace 函数从另一个问题的答案从 JS 转换为 PHP。(用 SPAN 标签包围 HTML 文本中的单个单词?)
<?php
echo wrap_words('span', 'Lorem ipsum dolor sit amet, <a href="#">consectetuer adipiscing</a> elit, <strong>tincidunt</strong> ut volutpat.');
function wrap_words($tag, $text) {
$document = new DOMDocument();
$fragment = $document->createDocumentFragment();
$fragment->appendXml($text);
walk($tag, $fragment);
$html = $document->saveHtml($fragment);
// using saveHTML with a documentFragment can leave an invalid "<>"
// at the beginning of the string - remove it
return preg_replace('/^<>/', '', $html);
}
function walk($tag, $root)
{
if ($root->nodeType == XML_TEXT_NODE)
{
doReplace($tag, $root);
return;
}
$children = $root->childNodes;
for ($i = $children->length - 1; $i >= 0; $i--)
{
walk($tag, $children->item($i));
}
}
function doReplace($tag, $text)
{
$fragment = $text->ownerDocument->createDocumentFragment();
$fragment->appendXML(preg_replace('/\S+/', "<{$tag}>\$0</{$tag}>", $text->nodeValue));
$parent = $text->parentNode;
$children = $fragment->childNodes;
for ($i = $children->length - 1; $i >= 0; $i--)
{
$parent->insertBefore($children->item($i), $text->nextSibling);
}
$parent->removeChild($text);
}