使用 nom 5.0 解析数字
Parsing number with nom 5.0
我正在尝试使用 Nom 5.0 解析大文件(数十 GB)流式传输。解析器的一部分尝试解析数字:
use nom::IResult;
use nom::character::streaming::{char, digit1};
// use nom::character::complete::{char, digit1};
use nom::combinator::{map, opt};
use nom::multi::many1;
use nom::sequence::{preceded, tuple};
pub fn number(input: &str) -> IResult<&str, &str> {
map(
tuple((
opt(char('-')),
many1(digit1),
opt(preceded(char('.'), many1(digit1)))
)),
|_| "0"
)(input)
}
(显然,它不应该 return 所有数字都为“0”;这只是为了使函数尽可能简单。)对于这个解析器,我写了一个测试:
#[test]
fn match_positive_integer() {
let (_, res) = number("0").unwrap();
assert_eq!("0", res);
}
此测试失败并返回 Incomplete(Size(1))
,因为 "decimals" opt()
想要读取数据但不存在。如果我切换到 complete
版本的匹配器(如注释掉的行),则测试通过。
我认为这实际上会在生产中起作用,因为当抱怨不完整时它会被提供额外的数据,但我仍然想创建单元测试。此外,如果一个数字恰好是文件中输入的最后一位,那么在生产中就会出现这个问题。我如何说服流式 Nom 解析器没有更多可用数据?
可以说测试的原始形式是正确的:解析器无法确定给定的输入是否为数字,因此解析结果实际上尚未确定。在生产中,尤其是像您一样读取大文件时,已读取但待解析字节的缓冲区可能恰好在 可能 之间结束,除非它实际上是不是。然后,解析器需要保留其当前状态并请求更多输入以便它可以retry/continue。不要将 Incomplete
视为最终错误,而是将其视为 I don't even know: This could be an error depending on the next byte, this problem is undecidable as of yet!
.
您可以在您的顶级解析器 上使用 complete
-combinator ,所以当您实际上达到 EOF
时,您就会出错。 Incomplete
-results within 应该处理顶级解析器,例如通过将读取缓冲区扩大一定幅度并重试。
您可以将解析器包装在当前单元测试的本地 complete()
-解析器中并对其进行测试。有点像
#[test]
fn match_positive_integer() {
let (_, res) = complete(number("0")).unwrap();
assert_eq!("0", res);
}
我正在尝试使用 Nom 5.0 解析大文件(数十 GB)流式传输。解析器的一部分尝试解析数字:
use nom::IResult;
use nom::character::streaming::{char, digit1};
// use nom::character::complete::{char, digit1};
use nom::combinator::{map, opt};
use nom::multi::many1;
use nom::sequence::{preceded, tuple};
pub fn number(input: &str) -> IResult<&str, &str> {
map(
tuple((
opt(char('-')),
many1(digit1),
opt(preceded(char('.'), many1(digit1)))
)),
|_| "0"
)(input)
}
(显然,它不应该 return 所有数字都为“0”;这只是为了使函数尽可能简单。)对于这个解析器,我写了一个测试:
#[test]
fn match_positive_integer() {
let (_, res) = number("0").unwrap();
assert_eq!("0", res);
}
此测试失败并返回 Incomplete(Size(1))
,因为 "decimals" opt()
想要读取数据但不存在。如果我切换到 complete
版本的匹配器(如注释掉的行),则测试通过。
我认为这实际上会在生产中起作用,因为当抱怨不完整时它会被提供额外的数据,但我仍然想创建单元测试。此外,如果一个数字恰好是文件中输入的最后一位,那么在生产中就会出现这个问题。我如何说服流式 Nom 解析器没有更多可用数据?
可以说测试的原始形式是正确的:解析器无法确定给定的输入是否为数字,因此解析结果实际上尚未确定。在生产中,尤其是像您一样读取大文件时,已读取但待解析字节的缓冲区可能恰好在 可能 之间结束,除非它实际上是不是。然后,解析器需要保留其当前状态并请求更多输入以便它可以retry/continue。不要将 Incomplete
视为最终错误,而是将其视为 I don't even know: This could be an error depending on the next byte, this problem is undecidable as of yet!
.
您可以在您的顶级解析器 上使用 complete
-combinator ,所以当您实际上达到 EOF
时,您就会出错。 Incomplete
-results within 应该处理顶级解析器,例如通过将读取缓冲区扩大一定幅度并重试。
您可以将解析器包装在当前单元测试的本地 complete()
-解析器中并对其进行测试。有点像
#[test]
fn match_positive_integer() {
let (_, res) = complete(number("0")).unwrap();
assert_eq!("0", res);
}