Add date parsing
This commit is contained in:
parent
d29928aa3c
commit
33d0897096
|
@ -107,6 +107,7 @@ pub fn parse_date_field(s: &str) -> Result<Vec<Date>, Error> {
|
|||
Ok(dates)
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -158,3 +159,4 @@ mod test {
|
|||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{Color, Date, Error, GameResult};
|
||||
use chrono::{Datelike, NaiveDate};
|
||||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::{escaped_transform, tag, take_until1},
|
||||
|
@ -815,6 +816,81 @@ fn parse_text<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, String, E> {
|
|||
}
|
||||
}
|
||||
|
||||
enum DateSegment {
|
||||
One(i32),
|
||||
Two(i32, i32),
|
||||
Three(i32, i32, i32),
|
||||
}
|
||||
|
||||
fn parse_date_field<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, Vec<Date>, E> {
|
||||
|input| {
|
||||
let (input, first_date) = parse_date().parse(input)?;
|
||||
let (input, mut more_dates) = many0(parse_date_segment())(input)?;
|
||||
|
||||
let mut date_segments = vec![first_date];
|
||||
date_segments.append(&mut more_dates);
|
||||
|
||||
let mut dates = vec![];
|
||||
let mut most_recent = None;
|
||||
|
||||
for date_segment in date_segments {
|
||||
let new_date = match date_segment {
|
||||
DateSegment::One(v) => match most_recent {
|
||||
Some(Date::Year(_)) => Date::Year(v),
|
||||
Some(Date::YearMonth(y, _)) => Date::YearMonth(y, v as u32),
|
||||
Some(Date::Date(d)) => Date::Date(d.clone().with_day(v as u32).unwrap()),
|
||||
None => Date::Year(v),
|
||||
},
|
||||
DateSegment::Two(y, m) => Date::YearMonth(y, m as u32),
|
||||
DateSegment::Three(y, m, d) => {
|
||||
Date::Date(chrono::NaiveDate::from_ymd_opt(y, m as u32, d as u32).unwrap())
|
||||
}
|
||||
};
|
||||
dates.push(new_date.clone());
|
||||
most_recent = Some(new_date);
|
||||
}
|
||||
|
||||
Ok((input, dates))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_date_segment<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, DateSegment, E> {
|
||||
|input| {
|
||||
let (input, _) = tag(",")(input)?;
|
||||
let (input, element) = parse_date().parse(input)?;
|
||||
|
||||
Ok((input, element))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_date<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, DateSegment, E> {
|
||||
alt((parse_three(), parse_two(), parse_one()))
|
||||
}
|
||||
|
||||
fn parse_one<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, DateSegment, E> {
|
||||
parse_number().map(|year| DateSegment::One(year))
|
||||
}
|
||||
|
||||
fn parse_two<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, DateSegment, E> {
|
||||
|input| {
|
||||
let (input, year) = parse_number().parse(input)?;
|
||||
let (input, _) = tag("-")(input)?;
|
||||
let (input, month) = parse_number().parse(input)?;
|
||||
Ok((input, DateSegment::Two(year, month)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_three<'a, E: ParseError<&'a str>>() -> impl Parser<&'a str, DateSegment, E> {
|
||||
|input| {
|
||||
let (input, year) = parse_number().parse(input)?;
|
||||
let (input, _) = tag("-")(input)?;
|
||||
let (input, month) = parse_number().parse(input)?;
|
||||
let (input, _) = tag("-")(input)?;
|
||||
let (input, day) = parse_number().parse(input)?;
|
||||
Ok((input, DateSegment::Three(year, month, day)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -1059,3 +1135,58 @@ k<. Hard line breaks are all other linebreaks.",
|
|||
parse_tree::<nom::error::VerboseError<&str>>(&data).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod date_test {
|
||||
use super::*;
|
||||
use cool_asserts::assert_matches;
|
||||
|
||||
#[test]
|
||||
fn it_parses_a_year() {
|
||||
assert_matches!(parse_date_field::<nom::error::VerboseError<&str>>().parse("1996"), Ok((_, date)) => {
|
||||
assert_eq!(date, vec![Date::Year(1996)]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parses_a_month() {
|
||||
assert_matches!(
|
||||
parse_date_field::<nom::error::VerboseError<&str>>().parse("1996-12"),
|
||||
Ok((_, date)) => assert_eq!(date, vec![Date::YearMonth(1996, 12)])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parses_a_date() {
|
||||
assert_matches!(
|
||||
parse_date_field::<nom::error::VerboseError<&str>>().parse("1996-12-27"),
|
||||
Ok((_, date)) => assert_eq!(date, vec![Date::Date(
|
||||
NaiveDate::from_ymd_opt(1996, 12, 27).unwrap()
|
||||
)])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parses_date_continuation() {
|
||||
assert_matches!(
|
||||
parse_date_field::<nom::error::VerboseError<&str>>().parse("1996-12-27,28"),
|
||||
Ok((_, date)) => assert_eq!(date, vec![
|
||||
Date::Date(NaiveDate::from_ymd_opt(1996, 12, 27).unwrap()),
|
||||
Date::Date(NaiveDate::from_ymd_opt(1996, 12, 28).unwrap())
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parses_date_crossing_year_boundary() {
|
||||
assert_matches!(
|
||||
parse_date_field::<nom::error::VerboseError<&str>>().parse("1996-12-27,28,1997-01-03,04"),
|
||||
Ok((_, date)) => assert_eq!(date, vec![
|
||||
Date::Date(NaiveDate::from_ymd_opt(1996, 12, 27).unwrap()),
|
||||
Date::Date(NaiveDate::from_ymd_opt(1996, 12, 28).unwrap()),
|
||||
Date::Date(NaiveDate::from_ymd_opt(1997, 1, 3).unwrap()),
|
||||
Date::Date(NaiveDate::from_ymd_opt(1997, 1, 4).unwrap()),
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue