PHP查找特定字符串前的<p>标签并为其及相邻标签添加inline类
实现方案建议
现有基于纯字符串替换的实现存在几个明显缺陷:
- 仅匹配文本内容,若正文其他位置出现和h1相同的文字会触发误替换
- 没有处理p标签、h1标签已有class属性的场景,硬加属性会导致HTML结构错误
- 无法适配标签换行、多空格等非标准化的HTML格式场景
最优方案:DOM解析处理(最稳妥)
使用PHP内置的DOM扩展解析HTML结构,完全规避字符串匹配的各类边界问题,代码实现如下:
public static function markupH1TagWithinText($h1Text, $html) { $dom = new DOMDocument(); // 处理中文等特殊字符编码,避免生成多余html/body标签 $dom->loadHTML('<?xml encoding="UTF-8">' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $xpath = new DOMXPath($dom); // 精准定位文本匹配的h1节点 $h1Nodes = $xpath->query("//h1[normalize-space(text())='" . addslashes($h1Text) . "']"); if ($h1Nodes->length === 0) { return false; } $targetH1 = $h1Nodes->item(0); // 给h1追加inline类,兼容已有class的场景 $h1Class = $targetH1->getAttribute('class'); $targetH1->setAttribute('class', trim($h1Class . ' inline')); // 处理h1前面紧邻的p节点 $prevNode = $targetH1->previousSibling; while ($prevNode && $prevNode->nodeType !== XML_ELEMENT_NODE) { $prevNode = $prevNode->previousSibling; } if ($prevNode && $prevNode->tagName === 'p') { $pClass = $prevNode->getAttribute('class'); $prevNode->setAttribute('class', trim($pClass . ' inline')); } // 若需要给h1后紧邻的p节点也加类,取消注释下方代码即可 // $nextNode = $targetH1->nextSibling; // while ($nextNode && $nextNode->nodeType !== XML_ELEMENT_NODE) { // $nextNode = $nextNode->nextSibling; // } // if ($nextNode && $nextNode->tagName === 'p') { // $pClass = $nextNode->getAttribute('class'); // $nextNode->setAttribute('class', trim($pClass . ' inline')); // } return $dom->saveHTML(); }
该方案的优势:
- 完全基于DOM节点匹配,不会出现文本误匹配问题
- 自动兼容标签已有class的场景,不会破坏原有属性
- 自动忽略标签间的空格、换行等无意义字符,适配各类非标准化HTML格式
轻量方案:正则替换(适合结构固定的简单场景)
如果你的HTML结构固定,不想引入DOM解析的开销,可以用正则优化现有逻辑,比纯字符串匹配可靠性更高:
public static function markupH1TagWithinText($h1Text, $html) { $h1Quoted = preg_quote($h1Text, '/'); $pattern = [ // 匹配无class的h1标签 '/<h1>(' . $h1Quoted . ')<\/h1>/', // 匹配h1前面紧邻的无class的p标签 '/<p>(?=[^<]*<\/p>\s*<h1>' . $h1Quoted . '<\/h1>)/' ]; $replace = [ '<h1 class="inline">$1</h1>', '<p class="inline">' ]; $processedHtml = preg_replace($pattern, $replace, $html); return $processedHtml === $html ? false : $processedHtml; }
注意:正则方案仅适合HTML结构固定的场景,遇到标签已有属性、嵌套结构等复杂情况可能失效。
内容的提问来源于stack exchange,提问作者odd_duck
相关产品推荐
相关产品推荐

