我所尝试的一切都给了我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
包装类型创建一个解析器),但我想从整体上了解一下如何自己正确地构建解析器。
答案 0 :(得分:5)
Nom 4使部分数据的处理比以前的版本更加严格,以更好地支持流解析器和自定义输入类型。
有效地,如果解析器用完了输入并且不能说输入已用完是 meant ,它将始终返回Err::Incomplete
。这可能还包含有关解析器期望输入多少确切信息(在您的情况下,至少要多1个字节)。
它使用AtEof
特性来确定是否还有更多输入。对于false
和&str
,这总是返回&[u8]
,因为它们不提供有关它们是否完整的信息!
诀窍是更改解析器的输入类型,以明确表明输入将始终是完整的-为此,Nom提供了CompleteStr
和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。
答案 1 :(得分:5)
从nom 5.1.1
开始,用于组合解析器的方法已从基于宏的功能变为基于函数的功能,在nom's author blog中进行了更广泛的讨论。
随着这一更改,随后又出现了另一个问题-流和 complete 解析器现在位于不同的模块中,您需要明确选择所需的解析类型。通常,模块名称之间有明显的区别。
保留了旧的宏,但它们严格在流模式下工作。 CompleteStr
或CompleteByteSlice
之类的类型不见了。
要编写代码以寻求新的方法 ,您可以这样做(例如,注意导入中的显式character::complete
)
由于花了我一些时间来理解它-解析器,例如map_res
返回一个impl Fn(I) -> IResult<I, O2, E>
,这就是为什么要附加一对括号的原因-称其为闭包。 < / p>
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);
}
}