使用 nom 解析整数总是导致 Incomplete

Parsing an integer with nom always results in Incomplete

我尝试的一切都给了我 Incomplete(Size(1))。我现在最好的猜测是:

named!(my_u64(&str) -> u64,
    map_res!(recognize!(nom::digit), u64::from_str)
);

测试:

#[cfg(test)]
mod test {
    #[test]
    fn my_u64() {
        assert_eq!(Ok(("", 0)), super::my_u64("0"));
    }
}

有时在我的变体中(例如添加 complete!),如果我在末尾添加一个字符,我已经能够解析它。

我想为此获得一个有效的解析器(最终我希望这将允许我为 u64 包装器类型创建一个解析器)但我想要一个更大的图景掌握如何自己正确构建解析器。

Nom 4 对部分数据的处理比以前的版本更加严格,以更好地支持流式解析器和自定义输入类型。

实际上,如果解析器 运行 没有输入并且它无法判断 意味着 有 运行 输入,它总会 return Err::Incomplete。这也可能包含有关解析器期望输入的确切信息(在您的情况下,至少多 1 个字节)。

它确定是否有可能使用 AtEof 特征的更多输入。对于 &str&[u8],这总是 returns false,因为它们不提供有关它们是否完整的任何信息!

诀窍是更改解析器的输入类型以明确输入始终是完整的 - Nom 为此目的提供了 CompleteStr and CompleteByteSlice 包装器,或者您可以实现自己的输入类型。

因此,为了让您的解析器按预期工作,它需要看起来像这样:

named!(my_u64(CompleteStr) -> u64,
    map_res!(recognize!(nom::digit), u64::from_str)
);

你的测试看起来像这样:

#[cfg(test)]
mod test {
    #[test]
    fn my_u64() {
        assert_eq!(Ok((CompleteStr(""), 0)), super::my_u64(CompleteStr("0")));
    }
}

有关详细信息,请参阅 the announcement post for Nom 4

nom 5.1.1 开始,组合解析器的方法从基于宏更改为基于函数,nom's author blog 中讨论的范围更广。

除了这个变化之外还有另一个变化 - streamingcomplete 解析器现在驻留在不同的模块中,您需要明确选择哪种类型解析你需要的。通常与模块名称有明显区别。

保留了旧宏,但它们严格在流模式下工作。 CompleteStrCompleteByteSlice 等类型已消失。

要编写您要求新方法的代码,您可以像这样(注意在导入中显式character::complete[=36] =])

因为我花了一些时间来掌握它 - 解析器例如 map_res return a impl Fn(I) -> IResult<I, O2, E> 这就是为什么有额外的一对括号 - 调用关闭。

use std::str;
use nom::{
    IResult,
    character::complete::{
        digit1
    },
    combinator::{
        recognize,
        map_res
    }
};

fn my_u64(input : &str) -> IResult<&str, u64> {
    map_res(recognize(digit1), str::parse)(input)
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_my_u64() {
        let input = "42";
        let num = my_u64(input);
        assert_eq!(Ok(("", 42u64)), num);
    }
}