使用 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 中讨论的范围更广。
除了这个变化之外还有另一个变化 - streaming 和 complete 解析器现在驻留在不同的模块中,您需要明确选择哪种类型解析你需要的。通常与模块名称有明显区别。
保留了旧宏,但它们严格在流模式下工作。 CompleteStr
或 CompleteByteSlice
等类型已消失。
要编写您要求新方法的代码,您可以像这样(注意在导入中显式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);
}
}
我尝试的一切都给了我 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 中讨论的范围更广。
除了这个变化之外还有另一个变化 - streaming 和 complete 解析器现在驻留在不同的模块中,您需要明确选择哪种类型解析你需要的。通常与模块名称有明显区别。
保留了旧宏,但它们严格在流模式下工作。 CompleteStr
或 CompleteByteSlice
等类型已消失。
要编写您要求新方法的代码,您可以像这样(注意在导入中显式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);
}
}