Как мне разобрать заглавные строки в Nom? - PullRequest
3 голосов
/ 09 июля 2019

Я пишу парсеры в 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.

1 Ответ

3 голосов
/ 09 июля 2019

take_while распознает 0 или более символов, поэтому при использовании внутри many1, как вы это делали, он сначала анализирует всю строку "ADAM". Затем, когда many1 вызовет его снова, так как take_while может распознать пустую строку, оно выполнится успешно, но many0 и many1 будут защищены от этой ошибки: если базовый синтаксический анализатор не потребляет никакого ввода, они будут вернуть ошибку.

Для того, что вам нужно, функции uppercase_char должно быть достаточно, нет необходимости в recognize и many1. Хотя вы можете заменить take_while на take_while1

...