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

Nom解析器无法保留无效输入为剩余内容,测试失败

问题解决:parse_line空行解析失败的修复

问题根源

你的parse_line函数使用many1(many_till(space0, parse_token))强制要求至少解析一个token,但当输入为空行(仅\n)时,没有任何token可以匹配,导致many1解析失败,最终整个函数返回错误,不符合测试中Ok(("\n", vec![]))的预期。

解决方案

使用nom的opt组合器包裹原有的非空行解析逻辑,当非空行解析失败时(即遇到空行),直接返回空向量和原输入,满足测试要求。

修改后的完整代码:

use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::space0,
    multi::{many1, many_till},
    sequence::pair,
    combinator::opt,
    IResult,
};

fn parse_token(input: &str) -> IResult<&str, bool> {
    let (remaining, token) = alt((tag("0"), tag("1")))(input)?;
    Ok((remaining, token == "1"))
}

#[allow(dead_code)]
fn parse_line(input: &str) -> IResult<&str, Vec<bool>> {
    // 定义非空行的解析规则:至少一个token,后跟换行
    let parse_non_empty_line = pair(
        many1(many_till(space0, parse_token)),
        many_till(space0, tag("\n")),
    );

    match opt(parse_non_empty_line)(input) {
        Ok((remaining, Some((tokens_raw, _)))) => {
            // 转换解析出的token集合
            let tokens = tokens_raw.into_iter().map(|(_, token)| token).collect();
            Ok((remaining, tokens))
        }
        Ok((remaining, None)) => {
            // 空行或无法解析为非空行时,返回空向量和原输入
            Ok((remaining, vec![]))
        }
        Err(e) => Err(e),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_token_test() {
        assert_eq!(parse_token("0"), Ok(("", false)));
        assert_eq!(parse_token("1"), Ok(("", true)));
    }

    #[test]
    fn parse_line_test() {
        assert_eq!(parse_line("1\n"), Ok(("", vec![true])));
        assert_eq!(parse_line("0\n"), Ok(("", vec![false])));
        assert_eq!(
            parse_line("1 1 1 1\n"),
            Ok(("", vec![true, true, true, true]))
        );
    }

    #[test]
    fn parse_line_repeat() {
        let rtn = parse_line("1\n 1\n");
        assert_eq!(rtn, Ok((" 1\n", vec![true])));
        let rtn = parse_line(rtn.unwrap().0);
        assert_eq!(rtn, Ok(("", vec![true])));
        let rtn = parse_line("1\n 1\n\n");
        assert_eq!(rtn, Ok((" 1\n\n", vec![true])));
        let rtn = parse_line(rtn.unwrap().0);
        assert_eq!(rtn, Ok(("\n", vec![true])));
        let rtn = parse_line(rtn.unwrap().0);
        assert_eq!(rtn, Ok(("\n", vec![])));
    }    
}

代码说明

  1. opt组合器的作用:尝试执行传入的解析器,成功则返回Some(解析结果),失败则返回None且不消耗输入,完美适配空行的处理场景。
  2. 分支处理:
    • 非空行解析成功时,按原有逻辑转换token并返回结果;
    • 解析失败时(对应空行),直接返回空向量和原输入,完全匹配测试中的预期。
  3. 兼容性:原有非空行的解析逻辑未被修改,保证parse_line_test和parse_token_test依然可以通过。

修改后运行cargo test,所有测试都会成功通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:14:51