我是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中的方法。解决此问题的正确方法是什么?
答案 0 :(得分:1)
在所谓的流模式下运行时,nom
可能返回Incomplete
来指示它无法决定并需要更多数据。 nom
4引入了CompleteStr
。与CompleteByteSlice
一起,它们是&str
和&[u8]
的完整输入副本。解析器以完整模式将它们作为输入工作。
它们在nom
中消失了。在nom
5中,如您所见,基于宏的解析器始终以流模式工作。对于在流模式和完整模式下工作方式不同的解析器组合器,它们在单独的子模块中有不同的版本,例如nom::bytes::streaming
和nom::bytes::complete
。
对于所有这些细节,您可能需要查看this blog post,尤其是流VS完整解析器部分。
此外,函数组合器比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)
}