如何匹配正则表达式但在 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"),"test1-test2")));
    assert_eq!(name("test1.test2"),"test1.test2")));
    assert_eq!(name("test1_test2"),"test1_test2")));
    assert_eq!(name("Test1_Test2"),"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 之类的函数,这会正常工作,但这不会捕获我想要的正则表达式。

我可以自己编写代码并以某种方式检查第一个字符和随后的字符,但是我还有其他几种情况需要解析不同的正则表达式,并且它将变得无法维护。

获取与正则表达式匹配的部分并继续解析较大输入的其余部分的正确方法是什么?

解决方法

我试过了,部分问题出在正则表达式末尾的 $ 上。这将告诉正则表达式匹配器匹配整个输入直到结束,否则将不匹配。

另一个问题是 re_match()。从 nom 文档中,如果找到匹配项, re_match 将返回整个输入(无论匹配多少个字符)。您想要的是 re_find() 函数,它将返回第一个匹配项。