寻求可避免自嵌套的Markdown内联元素解析算法
问题
我需要一种能够解析Markdown内联元素(如用**或__包裹的粗体、用*或_包裹的斜体等)且避免此类元素自嵌套的算法。
CommonMark的相关算法不阻止自嵌套,例如输入**some **random** text**会被解析为<strong>some <strong>random</strong> text</strong>。由于嵌套<strong>或<em>标签无法增强文本的粗体或斜体效果,我更希望保留无额外样式作用的星号,输出应为<strong>some **random** text</strong>。
我知道可以在代码生成阶段而非解析阶段修复该问题,但这种方式需在令牌中添加源文本使用的分隔符,并不合理。CommonMark算法的问题在于其通过回溯为结束分隔符匹配最近的起始分隔符,会将已标记为强调的节点再次包裹。我曾考虑匹配最远的起始分隔符,但这会导致**some** random **text**被错误解析为单个粗体块。
请问是否存在此类现成算法?或能否修改CommonMark算法实现该需求?
参考:我用Rust实现的CommonMark算法(略作修改,不解析链接)
解决方案
现成算法参考
目前没有完全契合需求的主流通用算法,但部分轻量Markdown解析器(比如静态站点生成器中的简化实现)会默认限制强调元素的嵌套,这类项目的源码逻辑可以直接参考——它们通常会在扫描分隔符时,跳过已处于同类型强调节点内部的分隔符,避免自嵌套。
修改CommonMark算法的具体方案
基于你现有的Rust实现,可通过跟踪解析上下文状态来实现需求,核心逻辑如下:
- 维护解析状态栈:在解析内联元素的过程中,用栈记录当前所处的强调节点类型(如
Strong/Emphasis)以及对应的分隔符类型(**/__或*/_)。 - 过滤同类型内部的分隔符:
- 当扫描到起始分隔符时,若栈顶是同类型的强调节点,直接将该分隔符当作普通文本处理,不触发新节点创建;
- 当扫描到结束分隔符时,仅当栈顶是对应类型的节点时,才完成节点闭合,否则视为普通文本。
- 保留原有有效性检查:继续沿用CommonMark对分隔符的基础校验(比如是否被转义、是否处于代码块/行内代码中),仅在匹配前增加上下文状态判断。
示例验证
处理
**some **random** text**:- 第一个
**触发创建Strong节点并压入栈; - 遇到第二个
**时,因栈顶是Strong节点,直接将这两个*作为普通文本加入当前节点; - 遇到第三个
**时,匹配栈顶的Strong节点,完成闭合并弹出栈;
最终输出<strong>some **random** text</strong>,符合预期。
- 第一个
处理
**some** random **text**:- 第一个
**创建Strong节点,扫描到对应结束**时闭合节点,栈清空; - 后续的
**因栈为空,会创建新的Strong节点,不会被错误合并成单个块。
- 第一个
这种修改完全在解析阶段完成,无需在令牌中额外存储分隔符信息,符合你的设计要求。
内容的提问来源于stack exchange,提问作者user8649828

