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

基于winnow 0.6.7,如何处理非行尾合法出现的EOF?

Winnow 0.6.7 处理EOF与末尾空行的最佳实践

核心问题分析

你遇到的无限循环问题,本质是eof解析器仅检查输入是否结束,不消耗任何内容。当把它放入repeat这类循环解析器时,每次匹配eof都不会推进输入位置,导致repeat反复尝试匹配,触发winnow的无限循环防护机制。

最佳实践方案

核心思路是拆分解析逻辑,避免将eof放入循环解析器中,同时覆盖所有边缘场景(带换行的行、无换行的末尾有效行、末尾空行):

1. 定义基础解析单元

首先实现行终止符、行内容的基础解析器:

use winnow::{
    combinator::{alt, opt, terminated},
    token::{newline, crlf},
    Parser,
};

// 定义行类型,根据你的需求调整
#[derive(Debug, PartialEq)]
enum Line {
    Directive(String, u32, u32),
    Mode(u32, String),
    Empty,
}

// 匹配\n或\r\n行终止符
fn line_ending(input: &mut &str) -> winnow::PResult<()> {
    alt((crlf, newline)).parse_next(input).map(|_| ())
}

// 解析非空行(根据你的指令格式实现)
fn non_empty_line(input: &mut &str) -> winnow::PResult<Line> {
    alt((
        // 解析.DIRECTIVE行,跳过末尾注释
        (".DIRECTIVE ", winnow::ascii::dec_uint, " ", winnow::ascii::dec_uint, winnow::token::take_until("//"))
            .map(|(_, a, _, b, _)| Line::Directive(".DIRECTIVE".into(), a, b)),
        // 解析.MODE行
        (".MODE ", winnow::ascii::dec_uint, " \"", winnow::token::take_until("\""), "\"")
            .map(|(_, num, _, content, _)| Line::Mode(num, content.into())),
    )).parse_next(input)
}

// 解析行内容:可以是非空行或空行(空字符串)
fn line_content(input: &mut &str) -> winnow::PResult<Line> {
    alt((
        non_empty_line,
        // 匹配空行(无任何内容)
        ().map(|_| Line::Empty),
    )).parse_next(input)
}

2. 实现完整文件解析

将文件解析拆分为两部分:

  • 批量解析所有带行终止符的行(包括空行)
  • 单独处理末尾可能存在的无行终止符的行(包括有效行或空行)
  • 最后用eof确保输入完全消耗,避免残留内容
fn parse_file(input: &mut &str) -> winnow::PResult<Vec<Line>> {
    // 解析所有带行终止符的行:行内容 + 换行符
    let mut lines = repeat(0.., terminated(line_content, line_ending)).parse_next(input)?;

    // 处理末尾无换行的行(可能是有效行或空行)
    if !input.is_empty() {
        lines.push(line_content.parse_next(input)?);
    } else {
        // 若输入已空,说明是末尾空行,需添加Empty行(不需要可省略此分支)
        lines.push(Line::Empty);
    }

    // 确保输入完全消耗,避免残留未解析内容
    winnow::combinator::eof.parse_next(input)?;

    Ok(lines)
}

3. 关键注意事项

  • 绝对不要将eof放入repeat、many0等循环解析器中,避免触发无限循环检查。
  • 末尾空行的处理可按需调整:若不需要将纯EOF视为空行,直接去掉else分支的lines.push(Line::Empty)即可。
  • 行尾注释可通过take_until("//")或skip_till规则跳过,无需额外复杂逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:36:04