0

I want to parse YMD date in four forms ("20190919", "2019.09.19", "2019-09-19", and "2019/09/19") by nom library.

I started with iso8601 parser which parse only "YYYY-MM-DD" form. And I tryed to match separator and reuse it for next matching like in regex (\d{4})([.-/]?)(\d{2})\2(\d{2}).

Turned out that this code works:

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,
        },
    ))
}

But obviously it looks weird.

Are there some nom tools to do it more appropriate way?

(This question about nom functionality, and how to do things there right. Not about just this particular example.)

Argentumbolo
  • 147
  • 1
  • 7

1 Answers1

1

Your solution is decent enough. There is only one suggestion I can offer really:

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,
    };

    ...
}

You may not be familiar with the syntax of accessing a tuple element directly. From rust book:

In addition to destructuring through pattern matching, we can access a tuple element directly by using a period (.) followed by the index of the value we want to access.

In this case, it saves you the awkwardness of trying to match the signature of two arms.

edwardw
  • 12,652
  • 3
  • 40
  • 51