synthphonia/text/parsing/
time.rs

1use std::collections::HashSet;
2
3use crate::galloc::TryAllocForExactSizeIter;
4use chrono::{Datelike, Month, NaiveDate, NaiveTime};
5use itertools::Itertools;
6use regex::Regex;
7
8use crate::value::ConstValue;
9use crate::{
10    expr::{ops, Expr},
11    galloc::AllocForExactSizeIter,
12    impl_basic, impl_op1_opt, new_op1_opt,
13    value::Value,
14};
15
16use super::ParsingOp;
17
18use chrono::Timelike;
19
20impl_basic!(ParseTime, "time.parse");
21impl crate::forward::enumeration::Enumerator1 for ParseTime {
22    fn enumerate(
23        &self,
24        this: &'static ops::Op1Enum,
25        exec: &'static crate::forward::executor::Executor,
26        opnt: [usize; 1],
27    ) -> Result<(), ()> {
28        Ok(())
29    }
30}
31
32impl crate::expr::ops::Op1 for ParseTime {
33    fn cost(&self) -> usize {
34        self.0
35    }
36    fn try_eval(&self, a1: crate::value::Value) -> (bool, crate::value::Value) {
37        match a1 {
38            crate::value::Value::Str(s1) => {
39                let mut flag = true;
40                let a = s1
41                    .iter()
42                    .map(|s1| {
43                        if let Some((s,c)) =  self.parse_into(s1).first() {
44                            c.as_i64().unwrap()
45                        } else {
46                            flag = false;
47                            0
48                        }
49                    }).galloc_scollect();
50                (flag, a.into())
51            }
52            _ => (false, Value::Null),
53        }
54    }
55}
56
57impl ParsingOp for ParseTime {
58    fn parse_into(&self, input: &'static str) -> std::vec::Vec<(&'static str, ConstValue)> {
59        let mut result: Vec<(&'static str, ConstValue)> = Vec::new();
60        let regex1 = Regex::new(r"(?<h>\d{1,2})(:(?<m>\d{1,2}))?(:(?<s>\d{1,2}))?(\s*(?<pm>p\.?m\.?|P\.?M\.?|a\.?m\.?|A\.?M\.?))?").unwrap();
61        for caps in regex1.captures_iter(input) {
62            let mut h = caps.name("h").unwrap().as_str().parse::<u32>().unwrap();
63            let m = caps.name("m").map(|a| a.as_str().parse::<u32>().unwrap()).unwrap_or(0);
64            let s = caps.name("s").map(|a| a.as_str().parse::<u32>().unwrap()).unwrap_or(0);
65            if let Some(a) = caps.name("pm") {
66                if a.as_str().starts_with('p') || a.as_str().starts_with('P') {
67                    if h != 12 { h += 12; }
68                } else if h == 12 { h = 0; }
69            }
70            if caps.name("m").is_some() || caps.name("s").is_some() || caps.name("pm").is_some() {
71                if let Some(a) = NaiveTime::from_hms_opt(h, m, s) {
72                    result.push((
73                        caps.get(0).unwrap().as_str(),
74                        a.num_seconds_from_midnight().into(),
75                    ))
76                }
77            }
78        }
79        result
80    }
81}
82
83pub fn detector(input: &'static str) -> bool {
84    let scanner = ParseTime(1);
85    !scanner.parse_into(input).is_empty()
86}
87
88#[cfg(test)]
89mod tests {
90
91    use crate::text::parsing::{ParseTime, ParsingOp};
92
93    #[test]
94    fn test1() {
95        let scanner = ParseTime(1);
96        println!("{:?}", scanner.parse_into("62"));
97        println!("{:?}", scanner.parse_into("6:25PM"));
98        println!("{:?}", scanner.parse_into("6:25:12 PM"));
99        println!("{:?}", scanner.parse_into("12:0:1 AM"));
100        println!("{:?}", scanner.parse_into("12am"));
101    }
102}