Parsing 使用解析器组合器解析带有转义字符的字符串?

Parsing 使用解析器组合器解析带有转义字符的字符串?,parsing,rust,Parsing,Rust,我正在尝试使用Rust中的库来解析字符串。我试图解析的真实数据如下所示: A79,216,0,4,2,2,N,"US\"PS" 因此,在该数据的末尾是一个带引号的字符串,但该字符串也将包含转义字符。我不知道如何解析其他引号之间的转义字符 extern板条箱解析器\u组合器; 使用self::parser_组合符::*; fn main(){ 让s=r#“HE\“LLO”#; 让data=many(满足(| c | c!=“”);//显然在转义时失败 让mut str|u parser=betw

我正在尝试使用Rust中的库来解析字符串。我试图解析的真实数据如下所示:

A79,216,0,4,2,2,N,"US\"PS"
因此,在该数据的末尾是一个带引号的字符串,但该字符串也将包含转义字符。我不知道如何解析其他引号之间的转义字符

extern板条箱解析器\u组合器;
使用self::parser_组合符::*;
fn main(){
让s=r#“HE\“LLO”#;
让data=many(满足(| c | c!=“”);//显然在转义时失败
让mut str|u parser=between(满足(|c | c=='”),满足(|c | c=='”),数据);
let result:result=str_parser.parse(s);
比赛结果{
Ok((值,)))=>println!(“{:?}”,值),
Err(Err)=>println!(“{}”,Err),
}
}
//=>“他\\”

以上代码将成功解析该字符串,但中间的转义字符将明显失败,最后打印出<代码>“He\”/CODE >

我想更改上面的代码,以便它打印出
“HE\\\”LLO“


如何做到这一点?

我有一个功能性很强的JSON解析器作为解析器组合器的基准,用于解析此类转义字符。我在下面添加了一个链接和一个略为简化的版本

fn json_char(input: State<&str>) -> ParseResult<char, &str> {
    let (c, input) = try!(satisfy(|c| c != '"').parse_state(input));
    let mut back_slash_char = satisfy(|c| "\"\\nrt".chars().find(|x| *x == c).is_some()).map(|c| {
        match c {
            '"' => '"',
            '\\' => '\\',
            'n' => '\n',
            'r' => '\r',
            't' => '\t',
            c => c//Should never happen
        }
    });
    match c {
        '\\' => input.combine(|input| back_slash_char.parse_state(input)),
        _    => Ok((c, input))
    }
}
fn json_char(输入:State)->ParseResult{
让(c,input)=try!(满足(|c | c!='“'))。解析_状态(input));
让mut back|slash|char=满足(|c|“\”\\nrt).chars().find(|x|*x==c).is|some()).map(|c|{
比赛c{
'"' => '"',
'\\' => '\\',
'n'=>'\n',
'r'=>'\r',
't'=>'\t',
c=>c//不应该发生
}
});
比赛c{
“\\”=>input.combine(| input | back |斜杠|字符.解析|状态(input)),
_=>正常((c,输入))
}
}


由于此解析器可能会使用1或2个字符,使用基本组合符是不够的,因此我们需要引入一个函数,该函数可以在解析的字符上进行分支。

我遇到了同样的问题,并最终得到了以下解决方案:

    (
        char('"'),
        many1::<Vec<char>, _>(choice((
            escaped_character(),
            satisfy(|c| c != '"'),
        ))),
        char('"')
    )

“\”他\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/code>可能会写得更好。
HE\\\\\\\\\\\\\\\\\\\\\\\♯‐设置原始字符串的样式,允许
r“…”
r#“…”
r##“…”
&c。
pub enum Operand {
    String { value: String },
}

fn escaped_character<I>() -> impl Parser<Input = I, Output = char>
    where
        I: Stream<Item = char>,
        I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    (
        char('\\'),
        any(),
    ).and_then(|(_, x)| match x {
        '0' => Ok('\0'),
        'n' => Ok('\n'),
        '\\' => Ok('\\'),
        '"' => Ok('"'),
        _ => Err(StreamErrorFor::<I>::unexpected_message(format!("Invalid escape sequence \\{}", x)))
    })
}

#[test]
fn parse_escaped_character() {
    let expected = Ok(('\n', " foo"));
    assert_eq!(expected, escaped_character().easy_parse("\\n foo"))
}

fn string_operand<I>() -> impl Parser<Input = I, Output = Operand>
    where
        I: Stream<Item = char>,
        I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    (
        char('"'),
        many1::<Vec<char>, _>(choice((
            escaped_character(),
            satisfy(|c| c != '"'),
        ))),
        char('"')
    )
        .map(|(_,value,_)| Operand::String { value: value.into_iter().collect() })
}

#[test]
fn parse_string_operand() {
    let expected = Ok((Operand::String { value: "foo \" bar \n baz \0".into() }, ""));
    assert_eq!(expected, string_operand().easy_parse(r#""foo \" bar \n baz \0""#))
}