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

使用Rust Nom v7解析Markdown代码块:终止条件匹配问题

Rust Nom v7 解析Markdown代码块的解决方案

核心思路

Nom v7 没有直接提供“读取直到指定解析器匹配”的预构建组合子,但可以通过many_till组合子实现——它会反复执行第一个解析器收集内容,直到第二个解析器成功匹配终止条件,最终返回收集到的内容和终止匹配结果。

具体实现

  • 定义终止条件解析器:实现匹配“单独一行的三个反引号(可后跟任意空白)”的逻辑,同时兼容代码块在文档末尾结束(无换行)的场景:
use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{newline, space0},
    combinator::eof,
    sequence::tuple,
    IResult,
};

fn code_block_end(input: &str) -> IResult<&str, ()> {
    let (input, _) = tuple((tag("```"), space0, alt((newline, eof))))(input)?;
    Ok((input, ()))
}
  • 收集代码块内容:用many_till结合逐字符读取的解析器,直到code_block_end匹配成功:
use nom::{multi::many_till, bytes::complete::take_while_m_n};

fn code_block_content(input: &str) -> IResult<&str, String> {
    let (input, (content_chunks, _)) = many_till(
        // 逐字符读取,确保不会跳过任何内容
        take_while_m_n(1, 1, |_| true),
        code_block_end
    )(input)?;
    Ok((input, content_chunks.into_iter().collect()))
}
  • 整合完整代码块解析器:加上代码块开头的三个反引号匹配逻辑:
fn markdown_code_block(input: &str) -> IResult<&str, String> {
    let (input, _) = tuple((tag("```"), space0, newline))(input)?;
    let (input, content) = code_block_content(input)?;
    Ok((input, content))
}

测试验证

对于包含内部```的代码块(示例用单引号替代反引号展示):

这里是代码内容
'''
继续写代码

实际测试替换回反引号后,解析器会正确跳过内部的反引号序列,仅当遇到单独一行的终止标记时才停止,原断言失败的问题会解决。

关键说明

  • 放弃take_until是正确选择,因为它仅基于字面量贪婪匹配,无法识别“单独一行”的上下文要求。
  • many_till是Nom处理“直到特定解析器匹配”场景的标准方案,完全无需正则,符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:10:31