From ce84ad4f0113554511dfcdbe1b4fa675d664a4c3 Mon Sep 17 00:00:00 2001 From: ren yuze Date: Tue, 18 Apr 2023 20:00:19 +0800 Subject: [PATCH] init --- .idea/.gitignore | 8 ++ .idea/candy.iml | 9 ++ .idea/modules.xml | 8 ++ candy.go | 2 + remind/parse.go | 232 +++++++++++++++++++++++++++++++++++++++++++ remind/parse_test.go | 15 +++ remind/sample.txt | 227 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 501 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/candy.iml create mode 100644 .idea/modules.xml create mode 100644 candy.go create mode 100644 remind/parse.go create mode 100644 remind/parse_test.go create mode 100644 remind/sample.txt diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/candy.iml b/.idea/candy.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/candy.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..bc415cb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/candy.go b/candy.go new file mode 100644 index 0000000..7d751e6 --- /dev/null +++ b/candy.go @@ -0,0 +1,2 @@ +// 幸せもアクビしてる +package candy diff --git a/remind/parse.go b/remind/parse.go new file mode 100644 index 0000000..fa604a0 --- /dev/null +++ b/remind/parse.go @@ -0,0 +1,232 @@ +package remind + +import ( + "b612.me/startimer" + "regexp" + "strconv" + "strings" + "time" +) + +func matchPattern01(str string) (startimer.StarTimer, bool) { + str = transChn(str) + var base = time.Now() + var rpt startimer.Repeats + var duration time.Duration + reg := regexp.MustCompile(`(每隔|每)?(\d{1,4}年)?(\d{1,5}个?月)?(\d{1,4}[明后大]{0,4}[日号天])?([上中下午夜早凌清晨傍晚里]+)?(\d{1,4}个?[点小时:]+)?(\d{1,4}[分:])?(\d{1,10}秒?)?`) + if reg.MatchString(str) { + pts := reg.FindStringSubmatch(str) + var timeParse = pts[5] + if pts[1] != "" { + rpt.Every = true + } + if pts[2] != "" { + if !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_YEAR, Value: uint32(getNumbers(pts[2]))}) + } else { + duration += time.Hour * 24 * 365 * time.Duration(getNumbers(pts[2])) + } + } + if pts[3] != "" { + if !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MONTH, Value: uint32(getNumbers(pts[3]))}) + } else { + duration += time.Hour * 24 * 30 * time.Duration(getNumbers(pts[3])) + } + } + if pts[4] != "" { + now := time.Now() + switch pts[4] { + case "明天": + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 24).Day())}) + case "后天": + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 48).Day())}) + case "大后天": + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 72).Day())}) + case "大大后天": + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 96).Day())}) + default: + if !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MONTH, Value: uint32(getNumbers(pts[4]))}) + } else { + duration += time.Hour * 24 * time.Duration(getNumbers(pts[4])) + } + } + } + setAsDate := false + if rpt.Every && timeParse != "" { + setAsDate = true + } else if rpt.Every && !strings.Contains(pts[6], "小时") { + setAsDate = true + base = time.Date(base.Year(), base.Month(), base.Day(), 0, 0, 0, 0, base.Location()) + } + if pts[6] != "" { + hour := uint32(getNumbers(pts[6])) + if timeParse == "下午" || strings.Contains(timeParse, "晚") || strings.Contains(timeParse, "夜") { + hour += 12 + } + if !setAsDate && !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_HOUR, Value: hour}) + } else if rpt.Every && !setAsDate { + duration += time.Hour * time.Duration(hour) + } else { + base.Add(time.Hour * time.Duration(hour)) + } + } else if timeParse != "" { + var hour uint32 + switch timeParse { + case "上午": + hour = 9 + case "中午": + hour = 8 + case "下午": + hour = 15 + case "傍晚": + hour = 18 + case "夜里", "晚上", "晚", "夜", "夜晚": + hour = 21 + case "凌晨": + hour = 0 + case "清晨": + hour = 6 + } + if !setAsDate { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_HOUR, Value: hour}) + } else { + base.Add(time.Hour * time.Duration(hour)) + } + } + if pts[7] != "" { + if !setAsDate && !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: uint32(getNumbers(pts[7]))}) + } else if rpt.Every && !setAsDate { + duration += time.Minute * time.Duration(uint32(getNumbers(pts[7]))) + } else { + base.Add(time.Minute * time.Duration(uint32(getNumbers(pts[7])))) + } + + } + if pts[8] != "" { + if !setAsDate && !rpt.Every { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(getNumbers(pts[8]))}) + } else if rpt.Every && !setAsDate { + duration += time.Second * time.Duration(uint32(getNumbers(pts[8]))) + } else { + base.Add(time.Second * time.Duration(uint32(getNumbers(pts[8])))) + } + } + if duration.Seconds() > 0 { + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(duration.Seconds())}) + } + return startimer.NewTimer(base, startimer.WithRepeats(&rpt)), true + } + return startimer.StarTimer{}, false +} + +/* +func matchPattern02(str string) (startimer.Repeats, bool) { + str = transChn(str) + var rpt startimer.Repeats + reg := regexp.MustCompile(`(每隔|每)?(周[周到1-6日]+)+([上中下午夜早凌清晨傍晚里]+)?(\d{1,4}[个点小时:]+)?(\d{1,4}[分:])?(\d{1,10}秒?)?`) + if reg.MatchString(str) { + pts := reg.FindStringSubmatch(str) + if pts[1] != "" { + rpt.Every = true + } + if pts[2] != "" { + if strings.Contains(pts[2], "到") { + se := strings.Split(pts[2], "到") + start := getNumbers(se[0]) + end := getNumbers(se[1]) + if end >= start { + for i := start; i <= end; i++ { + startimer.NextDayOfWeek() + } + } + } + } + } +} +*/ + +func transChn(msg string) string { + var res []rune + var tmpMap []rune + keyMap := map[rune]int{ + '零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '百': 100, '千': 1000, '万': 10000, '亿': 100000000, '两': 2, '俩': 2, + } + for _, v := range []rune(msg) { + if _, ok := keyMap[v]; ok { + tmpMap = append(tmpMap, v) + } else { + if len(tmpMap) != 0 { + res = append(res, []rune(strconv.Itoa(transfer(string(tmpMap))))...) + tmpMap = []rune{} + } + res = append(res, v) + } + } + return string(res) +} +func transfer(msg string) int { + keyMap := map[rune]int{ + '零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '百': 100, '千': 1000, '万': 10000, '亿': 100000000, '两': 2, '俩': 2, + } + result := 0 + secCache := 0 + thrCache := 0 + fKWord := map[rune]int{'百': 100, '千': 1000, '万': 10000, '亿': 100000000} + for _, num := range []rune(msg) { + if _, match := fKWord[num]; !match { + if num == '十' && thrCache != 0 { + thrCache *= keyMap[num] + } else { + thrCache += keyMap[num] + } + } else { + if fKWord[num] < 10000 { + secCache += thrCache * fKWord[num] + thrCache = 0 + } else { + secCache += thrCache + thrCache = 0 + if secCache == 0 { + result *= fKWord[num] + continue + } + result += secCache * fKWord[num] + secCache = 0 + } + } + } + + result += secCache + thrCache + return result +} + +func getNumbers(s string) float64 { + res := "" + isNegative := false + + for _, c := range s { + switch { + case c == '-' && len(res) == 0: + isNegative = true + case c >= '0' && c <= '9': + res += string(c) + case c == '.' && !strings.Contains(res, "."): + res += string(c) + } + } + + if res == "" { + return 0 + } + + if isNegative { + res = "-" + res + } + + num, _ := strconv.ParseFloat(res, 64) + return num +} diff --git a/remind/parse_test.go b/remind/parse_test.go new file mode 100644 index 0000000..cbde165 --- /dev/null +++ b/remind/parse_test.go @@ -0,0 +1,15 @@ +package remind + +import ( + "fmt" + "testing" +) + +func TestParse(t *testing.T) { + a, _ := matchPattern01("每两个小时") + fmt.Println(a.NextTimer(), a.BaseDate()) + a, _ = matchPattern01("每五个月零二十五天三小时25分15秒") + fmt.Println(a.NextTimer(), a.BaseDate()) + a, _ = matchPattern01("5月23日3点24分12秒") + fmt.Println(a.NextTimer(), a.BaseDate()) +} diff --git a/remind/sample.txt b/remind/sample.txt new file mode 100644 index 0000000..f59bffa --- /dev/null +++ b/remind/sample.txt @@ -0,0 +1,227 @@ +package main + +import ( + "fmt" + "regexp" + "time" +) + +func main() { + tests := []string{"明天下午三点", "每两天两个小时", "每天上午", "周五上午", "每周四下午三点", "2023年6月18日上午8点49", "大后天的16:00", "每隔5天提醒我吃饭", "从后天上午9点开始,每3天"} + + for _, test := range tests { + fmt.Printf("测试文本:%s\n", test) + + // 匹配时间模板 + pattern1 := `(?P\d{4})年(?P\d{1,2})月(?P\d{1,2})日(?P\d{1,2}):(?P\d{1,2})` + pattern2 := `(每)?((?P\d+)天)?((?P\d+)个小时)?((?P\d+)分)?((?P\d+)秒)?(后|钟|日)?` + pattern3 := `(?P周[一二三四五六日])?((?P[上中下])*午)?(?P\d{1,2}):?(?P\d{0,2})` + pattern4 := `每((?P[天周])[一二三四五六七八九十]+)?(?P\d{1,2}):(?P\d{2})` + pattern5 := `(?P[今明后大]?[0-9]{0,2}年[0-9]{0,2}月[0-9]{0,2}日)?(?P周[一二三四五六日])?((?P[上中下])*午)?(?P\d{1,2}):?(?P\d{0,2})` + + match1, _ := regexp.MatchString(pattern1, test) + match2, _ := regexp.MatchString(pattern2, test) + match3, _ := regexp.MatchString(pattern3, test) + match4, _ := regexp.MatchString(pattern4, test) + match5, _ := regexp.MatchString(pattern5, test) + + // 判断是否存在循环提醒 + isLoop := false + if match2 { + isLoop = matchDayHourMinSecLoop(test) + } else if match4 { + isLoop = matchEveryDayLoop(test) + } else if match5 { + isLoop = matchStartLoop(test) + } + + if match1 || match2 || match3 || match4 || match5 { + fmt.Println("匹配到时间!") + if isLoop { + fmt.Println("存在循环提醒!") + } else { + fmt.Println("不存在循环提醒!") + } + } else { + fmt.Println("未匹配到时间!") + } + } +} + +// 判断每天、每两天、每小时、每分钟循环提醒 +func matchDayHourMinSecLoop(text string) bool { + pattern := `(每)?((?P\d+)天)?((?P\d+)个小时)?((?P\d+)分)?((?P\d+)秒)?(后|钟|日)?` + re := regexp.MustCompile(pattern) + match := re.FindStringSubmatch(text) + + // 判断是否存在循环提醒 + for _, group := range match[1:] { + if len(group) > 0 { + return true + } + } + + return false +} + +// 判断每天、每周循环提醒 +func matchEveryDayLoop(text string) bool { + pattern := `每((?P[天周])[一二三四五六七八九十]+)?(?P\d{1,2}):(?P\d{2})` + re := regexp.MustCompile(pattern) + match := re.FindStringSubmatch(text) + + if len(match[1]) > 0 || len(match[2]) > 0 { + return true + } + + return false +} + +// 判断从某个时间开始,每隔多长时间循环提醒 +func matchStartLoop(text string) bool { + pattern := `(?P[今明后大]?[0-9]{0,2}年[0-9]{0,2}月[0-9]{0,2}日)?(?P周[一二三四五六日])?((?P[上中下])*午)?(?P\d{1,2}):?(?P\d{0,2})开始,每隔(?P\d+)([天时分])(\d+)?(\w+)?(\d+秒)?` + re := regexp.MustCompile(pattern) + match := re.FindStringSubmatch(text) + + loopDuration := parseDuration(match[2], match[3], match[4], match[5], match[6]) + if loopDuration > 0 { + return true + } + + return false +} + +// 解析时间段 +func parseDuration(d, h, m, s, unit string) time.Duration { + duration := time.Duration(0) + + if len(d) > 0 { + duration += 24 * time.Duration(parseInt(d)) * time.Hour + } + + if len(h) > 0 { + duration += time.Duration(parseInt(h)) * time.Hour + } + + if len(m) > 0 { + duration += time.Duration(parseInt(m)) * time.Minute + } + + if len(s) > 0 { + duration += time.Duration(parseInt(s)) * time.Second + } + + switch unit { + case "时": + duration += time.Hour + case "分": + duration += time.Minute + case "秒": + duration += time.Second + } + + return duration +} + +// 将中文数字转换为整数 +func parseInt(chineseNum string) int { + chineseNums := map[string]int{ + "零": 0, + "一": 1, + "二": 2, + "三": 3, + "四": 4, + "五": 5, + "六": 6, + "七": 7, + "八": 8, + "九": 9, + "十": 10, + "两": 2, // 特殊情况,"两"表示2 + } + + num := 0 + for i := 0; i < len(chineseNum); i++ { + curNum := chineseNums[string(chineseNum[i])] + if curNum == 10 { + if num == 0 { + num = 10 + } else { + num *= 10 + } + } else { + num += curNum + } + } + + return num +} + + + + + + + + + + + +package main + +import ( + "fmt" + "regexp" +) + +func main() { + tests := []string{"明天下午三点五十八秒", "每两天两个小时十分三秒", "每天上午零点", "周五上午一时", "每周四下午三点四十二秒", "2023年6月18日上午8点49分58秒", "大后天的16:00:23", "每隔5天提醒我吃饭", "从后天上午9点开始,每3天"} + + // 模式1:日期时间模式,如:2021年8月1日下午3点20分 + pattern1 := `(\d{4}年\d{1,2}月\d{1,2}日)?([上中下午夜早]+)?(\d{1,2}[点时](\d{1,2}分)?(\d{1,2}秒)?)?` + + // 模式2:大后天模式,如:大后天的16:00 + pattern2 := `[大明后](前|后)?天的(\d{1,2}:[0-5]\d:[0-5]\d)` + + // 模式3:每隔多长时间模式,如:每两天两个小时,每隔5天提醒我吃饭 + pattern3 := `每隔(\d+)([天时分])(\d+)?(\w+)?(\d+秒)?` + + // 模式4:频率模式,如:每天上午,周五上午,每周四下午三点 + pattern4 := `每([天周])?([一二三四五六七八九十]+)日?([上中下午夜早]+)?(\d{1,2}:[0-5]\d(:[0-5]\d)?)?` + + // 模式5:从某个日期时间开始,每隔多长时间,如:从后天上午9点开始,每3天 + pattern5 := `从([大明后](前|后)?天的|今天|明天|后天|(\d{4}年\d{1,2}月\d{1,2}日))(\d{1,2}:[0-5]\d(:[0-5]\d)?)?开始,每隔(\d+)([天时分])(\d+)?(\w+)?(\d+秒)?` + + for _, test := range tests { + fmt.Printf("测试文本:%s\n", test) + + match1, _ := regexp.MatchString(pattern1, test) + if match1 { + fmt.Println("匹配到时间!") + } else { + fmt.Println("未匹配到时间!") + } + + match2, _ := regexp.MatchString(pattern2, test) + if match2 { + fmt.Println("匹配到大后天!") + } + + match3, _ := regexp.MatchString(pattern3, test) + if match3 { + fmt.Println("匹配到每隔时间!") + } + + match4, _ := regexp.MatchString(pattern4, test) + if match4 { + fmt.Println("匹配到频率时间!") + } + + match5, _ := regexp.MatchString(pattern5, test) + if match5 { + fmt.Println("匹配到从某个时间开始,每隔多长时间!") + } + + fmt.Println("") + } +}