5

我尝试的一切都给了我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包装器类型创建一个解析器)但更大的图景我想了解如何自己正确构建解析器。

4

2 回答 2

10

至于nom 5.1.1组合解析器的方法从基于宏变为基于函数,在nom 的作者博客中进行了更广泛的讨论。

随着这一变化,另一个随之而来的 -流式解析器和完整解析器现在驻留在不同的模块中,您需要明确选择所需的解析类型。大多数情况下,模块名称有明显的区别。

旧的宏被保留,但它们严格在流模式下工作。像CompleteStror的类型CompleteByteSlice已经消失了。

要编写您要求的新方法的代码,例如可以这样做(注意character::complete在导入中显式)

因为我花了一些时间来掌握它——例如解析器map_res返回 aimpl 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);
    }
}
于 2020-04-27T21:07:48.107 回答
6

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

实际上,如果解析器用完输入并且它无法判断它是否意味着已经用完输入,它总是会返回Err::Incomplete. 这还可能包含有关解析器期望的确切输入量的信息(在您的情况下,至少多 1 个字节)。

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

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

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

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")));
    }
}

有关详细信息,请参阅Nom 4 的公告帖子

于 2018-07-10T12:49:29.103 回答