我是Rust和Nom的新手,我试图解析一个(单)加引号的字符串,其中可能包含转义的引号,例如'foo\' 🤖 bar''λx → x'''' '

我找到了escaped!宏,其documentation表示:



因为我想在匹配器中匹配除“正常字符”之外的任何反斜杠,所以我尝试使用 take_till! :

    named!(till_backslash<&str, &str>, take_till!(|ch| ch == '\\'));
    named!(esc<&str, &str>, escaped!(call!(till_backslash), '\\', one_of!("'n\\")));

    let (input, _) = nom::character::complete::char('\'')(input)?;
    let (input, value) = esc(input)?;
    let (input, _) = nom::character::complete::char('\'')(input)?;

    // … use `value`

但是,当尝试解析'x'时,这将返回Err(Incomplete(Size(1)))。搜索时,人们通常建议使用CompleteStr,但这不是Nom 5中的方法。解决此问题的正确方法是什么?

最佳答案

当在所谓的流模式下运行时,nom可能会返回Incomplete来指示它无法确定并需要更多数据。 nom 4引入了CompleteStr。除了CompleteByteSlice之外,它们都是&str&[u8]的完整输入对应物。解析器将它们作为完成模式下的输入工作。

它们已在nom 5中消失了。在nom 5中,基于宏的解析器始终以流模式工作,正如您所观察到的。对于将在流模式和完整模式下工作的解析器组合器,它们在不同的子模块中有不同的版本,例如nom::bytes::streamingnom::bytes::complete

对于所有这些细节,您可能需要 check out this blog post,尤其是Streaming VS complete解析器这一节。

同样,在nom 5中,函数组合器比宏组合器更可取。这是一种实现方法:

//# nom = "5.0.1"
use nom::{
    branch::alt,
    bytes::complete::{escaped, tag},
    character::complete::none_of,
    sequence::delimited,
    IResult,
};

fn main() {
    let (_, res) = parse_quoted(r#"'foo\' 🤖 bar'"#).unwrap();
    assert_eq!(res, r#"foo\' 🤖 bar"#);
    let (_, res) = parse_quoted("'λx → x'").unwrap();
    assert_eq!(res, "λx → x");
    let (_, res) = parse_quoted("'  '").unwrap();
    assert_eq!(res, "  ");
    let (_, res) = parse_quoted("''").unwrap();
    assert_eq!(res, "");
}

fn parse_quoted(input: &str) -> IResult<&str, &str> {
    let esc = escaped(none_of("\\\'"), '\\', tag("'"));
    let esc_or_empty = alt((esc, tag("")));
    let res = delimited(tag("'"), esc_or_empty, tag("'"))(input)?;

    Ok(res)
}

关于rust - 使用Nom 5解析带转义引号的单引号字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58904604/

10-10 17:02