0

我想通过nom库以四种形式(“20190919”、“2019.09.19”、“2019-09-19”和“2019/09/19”)解析 YMD 日期。

我从iso8601解析器开始,它只解析“YYYY-MM-DD”形式。我尝试匹配分隔符并将其重用于下一次匹配,如正则表达式(\d{4})([.-/]?)(\d{2})\2(\d{2})

原来这段代码有效:

fn parse_ymd(i: &[u8]) -> IResult<&[u8], DateType> {
    let (i, y) = year(i)?;

    // Match separator if it exist.
    let (i, sep) = opt(one_of(".-/"))(i)?;

    let (i, m) = month(i)?;

    // If first separator was matched then try to find next one.
    let (i, _) = if let Some(sep) = sep {
        tag(&[sep as u8])(i)?
    } else {
        // Support the same signature as previous branch.
        (i, &[' ' as u8][..])
    };

    let (i, d) = day(i)?;

    Ok((
        i,
        DateType::YMD {
            year: y,
            month: m,
            day: d,
        },
    ))
}

但显然它看起来很奇怪。

是否有一些 nom 工具可以以更合适的方式进行操作?

(这个关于nom功能的问题,以及如何在那里正确地做事。不仅仅是这个特定的例子。)

4

1 回答 1

1

您的解决方案足够体面。我只能提供一个建议:

fn parse_ymd(i: &[u8]) -> IResult<&[u8], DateType> {
    ...

    // If first separator was matched then try to find next one.
    let i = match sep {
        Some(sep) => tag(&[sep as u8])(i)?.0,
        _ => i,
    };

    ...
}

您可能不熟悉直接访问元组元素的语法。从锈书

除了通过模式匹配进行解构之外,我们还可以通过使用句点 (.) 后跟我们要访问的值的索引来直接访问元组元素。

在这种情况下,它可以避免尝试匹配两个手臂的签名的尴尬。

于 2019-09-19T15:21:10.710 回答