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

如何使用Rust Nom实现嵌套Markdown内联元素递归解析

解决Rust nom库实现Markdown嵌套内联解析的问题

核心问题分析

你的panic根源是unwrap()在解析失败时直接触发崩溃,加上递归解析时的边界处理缺失。要实现嵌套解析,关键是让每个格式元素的内容能递归调用内联解析器,而非直接处理原始文本。

步骤1:调整InlineElement为嵌套结构

确保枚举能容纳嵌套的内联元素:

#[derive(Debug, Clone)]
enum InlineElement {
    Text(String),
    Bold(Vec<InlineElement>),
    Italic(Vec<InlineElement>),
    Strikethrough(Vec<InlineElement>),
}

用Vec<InlineElement>替代原始字符串,让每个格式元素内部可以包含其他内联元素。

步骤2:修改解析器实现递归调用

每个格式解析器匹配到内容后,对内容部分递归调用parse_inline_text,同时避免使用unwrap(),改用nom的组合子处理错误:

use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    combinator::{map, value},
    multi::many0,
    sequence::{delimited, pair},
    IResult,
};

// 解析粗体,内部递归调用内联解析
fn parse_bold(input: &str) -> IResult<&str, InlineElement> {
    map(
        delimited(tag("**"), parse_inline_text, tag("**")),
        InlineElement::Bold,
    )(input)
}

// 解析斜体,内部递归调用内联解析
fn parse_italic(input: &str) -> IResult<&str, InlineElement> {
    map(
        delimited(tag("__"), parse_inline_text, tag("__")),
        InlineElement::Italic,
    )(input)
}

// 解析删除线,内部递归调用内联解析
fn parse_strikethrough(input: &str) -> IResult<&str, InlineElement> {
    map(
        delimited(tag("~~"), parse_inline_text, tag("~~")),
        InlineElement::Strikethrough,
    )(input)
}

// 解析普通文本,处理边界避免无限递归
fn parse_text(input: &str) -> IResult<&str, InlineElement> {
    // 匹配直到下一个格式标记,防止吞掉标记
    let (rest, text) = take_until(&["**", "__", "~~"][..])(input)?;
    if text.is_empty() {
        // 无文本时匹配单个字符,推进输入避免死循环
        let (rest, c) = nom::character::complete::anychar(input)?;
        Ok((rest, InlineElement::Text(c.to_string())))
    } else {
        Ok((rest, InlineElement::Text(text.to_string())))
    }
}

// 主内联解析器,组合所有解析规则
fn parse_inline_text(input: &str) -> IResult<&str, Vec<InlineElement>> {
    many0(alt((
        parse_bold,
        parse_italic,
        parse_strikethrough,
        parse_text,
    )))(input)
}

步骤3:关键注意事项

  • 禁止使用unwrap():nom的IResult需通过?或匹配Ok/Err处理错误,强行unwrap会在解析失败(比如格式标记不闭合)时直接panic。
  • 处理递归边界:parse_text必须处理空文本场景,否则当输入只剩格式标记时会陷入无限递归。
  • 测试嵌套场景:针对this is a **__bold and italic__** text这类输入,解析器会生成嵌套结构Bold(Italic(Text("bold and italic"))),完美处理嵌套格式。

如果仍有panic,建议打印parse_inline_text的返回值,定位具体失败步骤,排查是否存在格式标记不闭合或解析规则冲突的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:58:18