parsing - 如何解析 Nom 中的大写字符串?
问题描述
我在 Nom 5 中使用函数而不是宏编写解析器。我的目标是编写一个能够识别完全由大写字符组成的字符串的解析器。理想情况下,它将具有与alpha1相同的返回签名。
use nom::{
character::complete::{alpha1, char, line_ending, not_line_ending},
combinator::{cut, map, not, recognize},
error::{context, ParseError, VerboseError},
multi::{many0, many1},
IResult,
};
fn uppercase_char<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
take_while(move |c| chars.contains(c))(i)
}
// Matches 1 or more consecutive uppercase characters
fn upper1<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
recognize(many1(uppercase_char))(i)
}
尽管可以编译,但我编写的简单单元测试失败了:
#[test]
fn test_upper_string_ok() {
let input_text = "ADAM";
let output = upper1::<VerboseError<&str>>(input_text);
dbg!(&output);
let expected = Ok(("ADAM", ""));
assert_eq!(output, expected);
}
失败输出为
---- parse::tests::test_upper_string_ok stdout ----
[src/parse.rs:110] &output = Err(
Error(
VerboseError {
errors: [
(
"",
Nom(
Many1,
),
),
],
},
),
)
thread 'parse::tests::test_upper_string_ok' panicked at 'assertion failed: `(left == right)`
left: `Err(Error(VerboseError { errors: [("", Nom(Many1))] }))`,
right: `Ok(("ADAM", ""))`', src/parse.rs:112:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
解决方案
take_while
将识别 0 个或更多字符,因此当many1
您在内部使用时,它将首先解析整个"ADAM"
字符串。然后当many1
再次调用它时,由于take_while
可以识别一个空字符串,它会成功,但many0
有many1
一个防止该错误的保护:如果底层解析器没有消耗任何输入,它们将返回一个错误。
对于你所需要的,uppercase_char
功能应该足够了,不需要recognize
and many1
。虽然您可能想替换take_while
为take_while1
推荐阅读
- javascript - 文件系统访问 API createWritable() 方法在控制台中有效,但在脚本中无效
- mysql - 如何从具有旋转 IP 地址的 EC2 实例访问 Amazon RDS 上的 MySQL?
- bash - 如何从bash脚本中去除简单的引号
- c++ - 重复模板参数的快捷方式
- c# - 从 where 子句中删除列我可以使用吗?操作员
- r - R中未熔化表的问题
- arrays - 从用户搜索传递值数组时,Mongodb $in 因添加引号而失败
- android - 如果没有 @Provides-annotated 方法,就无法提供。公共抽象静态类 ApplicationC 实现 MyApplication_GeneratedInjector,
- javascript - 从javascript显示时钟/时间增量
- azure - 每次在 Azure DevOps 中签入门控更改都失败