Как сопоставить регулярное выражение, но вернуть оставшуюся часть ввода в Rust Nom?

Я пытаюсь использовать Nom 6.1.2 для анализа относительно простого Lisp-подобного языка, где мне нужно захватывать идентификаторы формы [a-z][a-zA-Z0-9_\-\.]. Я попытался использовать re_match, но ожидается, что весь input будет соответствовать не только первой части строки. Я хочу иметь возможность сопоставлять эти идентификаторы как часть более крупного контекста, поэтому я хочу, чтобы он возвращал оставшуюся часть ввода для передачи другим синтаксическим анализаторам в виде комбинатора синтаксического анализатора.

fn name(input: &str) -> IResult<&str, &str, VerboseError<&str>> {
    let re = Regex::new(r"^[A-Za-z][a-zA-Z0-9_\.\-]*$").unwrap();
    context("name", re_match(re))(input)
}

Я хочу пройти следующий тест:

#[test]
fn test_name() {
    assert_eq!(name("test"), Ok(("", "test")));
    assert_eq!(name("test1-test2"), Ok(("", "test1-test2")));
    assert_eq!(name("test1.test2"), Ok(("", "test1.test2")));
    assert_eq!(name("test1_test2"), Ok(("", "test1_test2")));
    assert_eq!(name("Test1_Test2"), Ok(("", "Test1_Test2")));
    assert!(name("123Test").is_err());

    //this last assertion fails
    assert_eq!(name("test1 test2$!%"), Ok((" test2$!%", "test1")));
}

Последнее утверждение в приведенном выше тесте не выполняется.

thread 'parser::tests::test_name' panicked at 'assertion failed: `(left == right)`
  left: `Err(Error(VerboseError { errors: [("test1 test2$!%", Nom(RegexpMatch)), ("test1 test2$!%", Context("name"))] }))`,
 right: `Ok((" test2$!%", "test1"))`', src\parser.rs:69:9
stack backtrace:

Если бы я использовал что-то вроде функции alphanumeric, это работало бы нормально, но это не захватывает нужное мне регулярное выражение.

Я мог бы вручную написать код и каким-то образом проверить первый символ и последующие, но у меня есть несколько других ситуаций, когда мне нужно анализировать разные регулярные выражения, и это станет недостижимым.

Как правильно выбрать часть, которая соответствует регулярному выражению, и продолжить синтаксический анализ остальной части более крупного ввода?


person jbx    schedule 16.03.2021    source источник
comment
используйте регулярное выражение при использовании Nom, чтобы победить все логики   -  person Stargateur    schedule 16.03.2021
comment
@Stargateur, о какой логике ты говоришь? regex идеально подходит для сопоставления идентификаторов и подобных вещей в комбинаторах синтаксического анализатора. Даже комбинаторы синтаксического анализатора в Scala без проблем работают с регулярными выражениями.   -  person jbx    schedule 16.03.2021


Ответы (1)


Я попробовал это, и часть проблемы связана с $ в конце регулярного выражения. Это скажет сопоставителю регулярных выражений сопоставить весь ввод до конца, иначе совпадения не будет.

Другая проблема связана с re_match (). Из документации nom re_match вернет весь ввод, если совпадение найдено (независимо от того, сколько символов совпало). Вам нужна функция re_find (), которая вернет первое совпадение.

person transistor    schedule 16.03.2021
comment
Без $ в конце он будет соответствовать остальной части ввода, включая несовпадающие символы после пробела, которые не имеют ничего общего с идентификатором. Утверждение все равно не удастся, потому что я получу Ok(("", "test1 test2$!%")) вместо Ok((" test2$!%", "test1")). - person jbx; 16.03.2021
comment
Извините, вам нужно удалить $ и, а также использовать функции re_find () вместо функции re_match (). Я обновлю ответ ... - person transistor; 17.03.2021
comment
Отлично, я не понимал, что могу использовать re_find с ^, чтобы заставить его соответствовать началу строки. - person jbx; 17.03.2021