如何在Nom中解析大写字符串?

时间:2019-07-09 16:08:32

标签: parsing rust nom

我正在使用功能而不是宏在Nom 5中编写解析器。我的目标是编写一个解析器,以识别完全由大写字符组成的字符串。理想情况下,它将具有与alpha1相同的返回签名。

constant ratio_ceiling : integer := (M + N - 1) / N;
constant ratio_floor   : integer := M / N;

尽管可以编译,但我编写的简单单元测试失败:

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

1 个答案:

答案 0 :(得分:3)

take_while可以识别0个或多个字符,因此,像您一样在many1中使用时,它将首先解析整个"ADAM"字符串。然后,当many1再次调用它时,由于take_while可以识别一个空字符串,它将成功执行,但是many0many1可以防止该错误:如果基础解析器没有消耗任何输入,它们将返回错误。

对于您所需要的,uppercase_char函数就足够了,不需要recognizemany1。尽管您可能希望将take_while替换为take_while1