首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >nom解析单独的列表

nom解析单独的列表
EN

Stack Overflow用户
提问于 2019-08-16 15:18:52
回答 1查看 731关注 0票数 1

我正试图用name5.0解析以下备用字符串

代码语言:javascript
复制
"A-Za-z0-9"

代码语言:javascript
复制
"A-Z|a-z|0-9"

我试过以下几种方法,但都没有用

代码语言:javascript
复制
pub enum Node {
    Range(Vec<u8>),
}

fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
    map(
        separated_list(
            alt((tag("|"), tag(""))),
            tuple((take(1usize), tag("-"), take(1usize))),
        ),
        |v: Vec<(&[u8], _, &[u8])>| {
            Node::Range(
                v.iter()
                    .map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
                    .flatten()
                    .collect(),
            )
        },
    )(input)
}

第二版。

代码语言:javascript
复制
fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
        alt((
            map(
                separated_list(tag("|"), tuple((take(1usize), tag("-"), take(1usize)))),
                |v: Vec<(&[u8], _, &[u8])>| {
                    Node::Range(
                        v.iter()
                            .map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
                            .flatten()
                            .collect(),
                    )
                },
            ),
            map(
                many1(tuple((take(1usize), tag("-"), take(1usize)))),
                |v: Vec<(&[u8], _, &[u8])>| {
                    Node::Range(
                        v.iter()
                            .map(|(s, _, e)| (s[0]..=e[0]).collect::<Vec<_>>())
                            .flatten()
                            .collect(),
                    )
                },
            ),
        ))(input)
    }



#[test]
fn parse_compound() {
    println!("{:?}", compound_range(b"A-Za-z0-9"));
    println!("{:?}", compound_range(b"A-Z|a-z|0-9"));
}

我可以让第一个或第二个解析,但永远不能两者兼而有之。有办法表达这一点吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-16 17:03:36

问题是,nom总是选择它所看到的第一条路径,这在某种程度上是可行的(就像它不需要消耗所有的输入一样)。因此,理想的做法是,在第一个"a-z" (或其他什么)之后将路径拆分为两个可能的路径之一:将|作为分隔符处理,或者不处理。

这是因为nom是一个解析器组合器库,不像regex那样工作,因为regex可以追溯到它需要找到的东西才能工作。

不管怎么说,这样的事情应该有效:

代码语言:javascript
复制
fn compound_range(input: &[u8]) -> IResult<&[u8], Node> {
    let single_range = |input| map(
        separated_pair(take(1usize), tag("-"), take(1usize)),
        |(l, r): (&[u8], &[u8])| (l[0], r[0])
    )(input);

    map(
        opt(
            map(
                pair(
                    single_range,
                    alt((
                        preceded(tag("|"), separated_nonempty_list(
                            tag("|"),
                            single_range,
                        )),
                        many0(single_range)
                    ))
                ),
                |(first, rest)| Node::Range(
                    std::iter::once(first).chain(rest).flat_map(|(l, r)| l..r).collect()
                )
            ),
        ),
        |o| o.unwrap_or_else(|| Node::Range(Vec::new()))
    )(input)
}

有更好的办法吗?可能吧。考虑到特定的任务,手动实现解析器的那一部分可能是有意义的。是这样的吗?可能吧。(我还没试过)

另外,要记住的是:如果您期望一些其他的东西适合它之后的模式,这可能会消耗太多。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57527176

复制
相关文章

相似问题

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