如何使用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
相关产品推荐
相关产品推荐

