You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求指导:如何用PHP实现类似维基百科的Markdown层级列表解析器

我来帮你拆解这个问题的实现逻辑,其实核心就是标题层级解析+栈式嵌套管理,一步步来:

1. 先明确规则:标题层级与等号的对应关系

从你的例子能看出来,等号的数量直接对应标题的嵌套层级:

  • ===aaa=== → 1级标题(最外层列表项)
  • ====bbb==== → 2级标题(1级的子项)
  • =====eee===== → 3级标题(2级的子项)
    简单说就是:层级数 = 两侧等号的最小数量 - 2(比如3个等号→3-2=1级,4个→4-2=2级)。如果遇到两侧等号数量不一致的情况(比如你例子里的===ccc====),取开头或结尾的最小等数来计算层级就好。

2. 核心实现思路:用栈跟踪嵌套结构

嵌套列表的难点在于处理层级的切换——什么时候开新的子列表,什么时候回到父列表。用栈来管理当前的层级上下文是最顺手的方式,逻辑如下:

  • 初始化一个空栈,用来记录当前所在的层级
  • 遍历每个解析后的标题(层级+内容):
    1. 回退到父层级:如果当前标题的层级比栈顶的层级低,就不断弹出栈顶元素,同时闭合对应的子列表标签,直到栈顶层级小于当前层级。
    2. 添加列表项:
      • 如果栈为空,说明是顶级标题,直接在最外层<ol>里加<li>
      • 如果栈顶层级+1等于当前层级,说明是父项的直接子项,先开一个子<ol>,再加<li>
    3. 记录当前层级:把当前层级压入栈,继续处理下一个标题
  • 遍历结束后,闭合所有未关闭的列表标签

3. 代码示例(Python)

先写一个标题解析函数,把每行文本转成(层级,内容)的格式:

def parse_title(line):
    line = line.strip()
    # 判断是否是标题行(首尾都是等号)
    if not (line.startswith('=') and line.endswith('=')):
        return None
    # 统计左侧等号数量
    left_eq_count = 0
    while left_eq_count < len(line) and line[left_eq_count] == '=':
        left_eq_count += 1
    # 统计右侧等号数量
    right_eq_count = 0
    while right_eq_count < len(line) and line[-1 - right_eq_count] == '=':
        right_eq_count += 1
    # 计算层级:取最小等号数-2
    level = min(left_eq_count, right_eq_count) - 2
    # 提取标题内容(去掉首尾等号后去空格)
    content = line[left_eq_count:-right_eq_count].strip()
    return (level, content)

再写生成嵌套有序列表的函数:

def titles_to_nested_ol(titles):
    stack = []
    html_parts = ['<ol>']
    
    for level, text in titles:
        # 回退到合适的父层级
        while stack and stack[-1] >= level:
            stack.pop()
            html_parts.append('</ol></li>')
        
        # 添加当前标题的列表项
        if not stack:
            # 顶级标题
            html_parts.append(f' <li>{text}')
        else:
            # 子标题,先开子列表
            html_parts.append(f' <ol><li>{text}')
        
        stack.append(level)
    
    # 闭合所有剩余的标签
    while stack:
        stack.pop()
        html_parts.append('</ol></li>')
    
    html_parts.append('</ol>')
    return '\n'.join(html_parts)

测试你的例子(修正了笔误的标题行):

input_lines = [
    '===aaa===',
    '====bbb====',
    '===ccc===',
    '====ddd====',
    '=====eee====='
]

# 提取所有标题
titles = []
for line in input_lines:
    title_info = parse_title(line)
    if title_info:
        titles.append(title_info)

# 生成HTML列表
print(titles_to_nested_ol(titles))

输出结果和你给的示例几乎一致:

<ol>
 <li>aaa
 <ol><li>bbb</ol></li>
 <li>ccc
 <ol><li>ddd
 <ol><li>eee</ol></li>
 </ol></li>
</ol>

4. 边界情况处理

  • 跳级标题:比如从1级直接跳到3级,你可以选择把3级当成2级处理,或者补全空的中间层级,具体看需求
  • 标题下的内容:如果要把标题下面的文本也放到列表项里,只需要在解析时把标题和后续内容关联起来,生成<li>时把内容加进去(比如<li>aaa<br>aaaaaaaaaaaaaaaaaa</li>)
  • 等号数量异常:比如一侧等号多一侧少,用最小等号数计算层级是最稳妥的方式

内容的提问来源于stack exchange,提问作者DolDurma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:49:04