正则表达式解析HTML时如何优先匹配最深层级的列表节点
解决方案1:使用正则负向断言匹配最内层节点
你可以通过负向零宽断言限制匹配的列表内部不包含同级的列表标签,就能直接命中最深层级的节点,循环处理即可实现从深到浅的解析:
$text = ' <ol> <li> <ul> <li>aaa</li> <li>bbb</li> </ul> </li> <li>fff</li> <li> <ol> <li>ccc</li> <li>ddd</li> </ol> </li> </ol> '; $processedContent = $text; $sortList = []; // 匹配不包含子ol/ul的最内层列表 while (preg_match('/<([ou]l)\b[^>]*>(?:(?!<\/?\1\b).)*<\/\1>/mis', $processedContent, $match)) { $sortList[] = $match[0]; // 替换已处理的节点,避免重复匹配 $processedContent = str_replace($match[0], '', $processedContent); } // 输出顺序为从最深到最浅,第一个元素就是你要的内层ol print_r($sortList);
解决方案2:使用DOM扩展解析(更稳定)
正则处理嵌套HTML结构存在较多边界情况,仅适合结构非常固定的简单场景,正式项目更推荐用PHP原生DOM扩展解析,DOM本身是树状结构,只要按节点深度倒序排序就能直接得到从深到浅的列表:
$dom = new DOMDocument(); // 关闭HTML语法报错提示 libxml_use_internal_errors(true); $dom->loadHTML($text); libxml_clear_errors(); $xpath = new DOMXPath($dom); // 查询所有ol和ul节点 $allLists = $xpath->query('//ol | //ul'); $listWithDepth = []; foreach ($allLists as $listNode) { // 计算节点深度 $depth = 0; $parent = $listNode->parentNode; while ($parent) { $depth++; $parent = $parent->parentNode; } $listWithDepth[] = [ 'depth' => $depth, 'html' => $dom->saveHTML($listNode), 'node' => $listNode ]; } // 按深度从高到低排序 usort($listWithDepth, function($a, $b) { return $b['depth'] - $a['depth']; }); // 遍历处理即可,第一个元素就是最深层级的列表 foreach ($listWithDepth as $item) { echo $item['html'] . PHP_EOL; }
如果要转换为OOP结构,直接读取$item['node']的子节点、属性等信息构造对应对象即可,不需要手动处理字符串匹配。
内容的提问来源于stack exchange,提问作者Lucian Gabriel Popescu
相关产品推荐
相关产品推荐

