首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用解析器-组合器解析带有转义字符的字符串?

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

Stack Overflow用户
提问于 2015-04-28 15:02:03
回答 2查看 871关注 0票数 4

我试图使用Rust中的合并库来解析一个字符串。我试图解析的真实数据如下所示:

代码语言:javascript
复制
A79,216,0,4,2,2,N,"US\"PS"

因此,该数据的末尾是引号中的字符串,但该字符串也将包含转义字符。我不知道如何在其他引号之间解析这些转义字符。

代码语言:javascript
复制
extern crate parser_combinators;

use self::parser_combinators::*;

fn main() {
    let s = r#""HE\"LLO""#;
    let data = many(satisfy(|c| c != '"')); // Fails on escaped " obviously
    let mut str_parser = between(satisfy(|c| c == '"'), satisfy(|c| c == '"'), data);
    let result : Result<(String, &str), ParseError> = str_parser.parse(s);
    match result {
        Ok((value, _)) => println!("{:?}", value),
        Err(err) => println!("{}", err),
    }
}

//=> "HE\\"

上面的代码将成功地解析该字符串,但在中间的转义字符上显然会失败,最后打印出"HE\\"

我想更改上面的代码,以便打印"HE\\\"LLO"

我该怎么做?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-28 18:42:38

我有一个主要是功能性的JSON解析器,作为解析器组合器的基准,它解析这种转义字符。我已经包括了一个链接到它和一个略为简化的版本,在下面。

代码语言:javascript
复制
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))
    }
}

字符

由于这个解析器可能需要一个或两个字符,所以仅仅使用原始组合器是不够的,所以我们需要引入一个函数,它可以分支到被解析的字符上。

票数 1
EN

Stack Overflow用户

发布于 2020-02-24 16:44:17

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

代码语言:javascript
复制
    (
        char('"'),
        many1::<Vec<char>, _>(choice((
            escaped_character(),
            satisfy(|c| c != '"'),
        ))),
        char('"')
    )

换句话说,字符串由"分隔,后面跟着many escaped_characters或任何不是结束"的东西,并由关闭"关闭。

下面是一个完整的例子,说明我是如何使用这个的:

代码语言:javascript
复制
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""#))
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29922918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档