You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
12 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package when
import (
"b612.me/startimer"
"errors"
"regexp"
"strconv"
"strings"
"time"
)
func legalCheck(limitCode string, baseDate time.Time, opts ...startimer.TimerOptions) (startimer.StarTimer, error) {
if limitCode == "" {
return startimer.NewTimer(baseDate, opts...)
}
timer, err := startimer.NewTimer(baseDate, opts...)
if err != nil {
return timer, err
}
if strings.Contains(limitCode, "今") {
if timer.NextTimer().Day() != time.Now().Day() {
return timer, errors.New("无法添加,指定的提醒时刻不在未来。")
}
}
return timer, err
}
func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, error) {
str = transChn(str)
var rpt startimer.Repeats
var duration time.Duration
reg := regexp.MustCompile(`(每隔|每)?(\d{0,4}年)?(\d{0,5}个?月)?(\d{0,4}[明后大]{0,4}[日号天])?([今天日上中下午夜早凌清晨傍晚里]+)?(\d{1,4}个?[点小时钟:]+)?(\d{0,4}半?[分::秒]?钟?)?(\d{0,10}半?秒?钟?)?(后)?`)
if reg.MatchString(str) {
pts := reg.FindStringSubmatch(str)
setAsDate := false
var timeParse = pts[5]
count := 1
if pts[1] != "" {
rpt.Every = true
count = 0
}
if pts[2] != "" {
if !rpt.Every {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_YEAR, Value: uint32(getNumbers(pts[2]))})
} else {
if getNumbers(pts[2]) == 0 {
setAsDate = true
} else {
duration += time.Hour * 24 * 365 * time.Duration(getNumbers(pts[2]))
}
}
}
if pts[3] != "" {
if !rpt.Every || setAsDate {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MONTH, Value: uint32(getNumbers(pts[3]))})
} else {
if getNumbers(pts[3]) == 0 {
setAsDate = true
} else {
duration += time.Hour * 24 * 30 * time.Duration(getNumbers(pts[3]))
}
}
}
if pts[4] != "" {
now := time.Now()
switch pts[4] {
case "天":
if rpt.Every {
setAsDate = true
}
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 setAsDate == rpt.Every {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(getNumbers(pts[4]))})
} else {
duration += time.Hour * 24 * time.Duration(getNumbers(pts[4]))
}
}
}
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())
// }
var hour uint32
if pts[6] != "" {
hour = uint32(getNumbers(pts[6]))
if hour < 12 && (timeParse == "下午" || strings.Contains(timeParse, "晚") || strings.Contains(timeParse, "夜")) {
hour += 12
}
if rpt.Every == setAsDate {
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 != "" {
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 pts[7] == "半" {
pts[7] = "30"
}
model := startimer.STAR_MINUTE
tmodel := time.Minute
if strings.Contains(pts[7], "秒") {
model = startimer.STAR_SECOND
tmodel = time.Second
}
if rpt.Every == setAsDate {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: model, Value: uint32(getNumbers(pts[7]))})
} else if rpt.Every && !setAsDate {
duration += tmodel * time.Duration(uint32(getNumbers(pts[7])))
} else {
base.Add(tmodel * time.Duration(uint32(getNumbers(pts[7]))))
}
} else if hour != 0 || pts[5] != "" {
if rpt.Every == setAsDate {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: 0})
}
}
if pts[8] != "" {
if pts[8] == "半" {
pts[8] = "30"
}
if rpt.Every == setAsDate {
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]))))
}
} else if hour != 0 || pts[5] != "" || pts[7] != "" {
if rpt.Every == setAsDate {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: 0})
}
}
if pts[9] != "" {
if rpt.Every {
return startimer.StarTimer{}, errors.New("Invalid Setences")
}
now := time.Now()
for _, sr := range rpt.Repeat {
switch sr.Unit {
case startimer.STAR_YEAR:
now = now.AddDate(int(sr.Value), 0, 0)
case startimer.STAR_MONTH:
now = now.AddDate(0, int(sr.Value), 0)
case startimer.STAR_DAY:
now = now.AddDate(0, 0, int(sr.Value))
case startimer.STAR_HOUR:
now = now.Add(time.Duration(sr.Value) * time.Hour)
case startimer.STAR_MINUTE:
now = now.Add(time.Duration(sr.Value) * time.Minute)
case startimer.STAR_SECOND:
now = now.Add(time.Duration(sr.Value) * time.Second)
}
}
return legalCheck(timeParse, time.Now(), startimer.WithStaticDate(now), startimer.WithRunCountLimit(count))
}
if duration.Seconds() > 0 {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(duration.Seconds())})
}
if rpt.Every == setAsDate {
rpt.Every = false
}
return legalCheck(timeParse, base, startimer.WithRepeats(&rpt), startimer.WithRunCountLimit(count))
}
return startimer.StarTimer{}, errors.New("no Match")
}
func matchPeroidPattern02(base time.Time, str string) (startimer.StarTimer, error) {
preReg := "(周|礼拜|星期)([1-7一二三四五六七日天])([0-9一二三四五六七八九零])"
preExp := regexp.MustCompile(preReg)
if preExp.MatchString(str) {
str = preExp.ReplaceAllString(str, "${1}${2}的${3}")
}
str = transChn(str)
str = strings.ReplaceAll(str, "周日", "周0")
str = strings.ReplaceAll(str, "礼拜天", "周0")
str = strings.ReplaceAll(str, "星期日", "周0")
str = strings.ReplaceAll(str, "星期天", "周0")
str = strings.ReplaceAll(str, "周天", "周0")
var rpt startimer.Repeats
reg := regexp.MustCompile(`(每)?([周星期礼拜日天]\d{0,1})到?([周礼拜星期日天]?\d{0,1})?的?([上中下午夜早凌清晨傍晚里]+)?(\d{1,4}[个点时::]+)?(\d{0,4}[分半:]?钟?)?(\d{1,10}秒?钟?)?`)
if reg.MatchString(str) {
pts := reg.FindStringSubmatch(str)
scs := len(strings.Split(pts[0], "周"))
if scs > 3 {
return startimer.StarTimer{}, errors.New("Invalid stings")
}
if scs == 3 && !strings.Contains(pts[0], "到") {
return startimer.StarTimer{}, errors.New("Invalid stings")
}
if pts[2] != "" {
if len(pts[3]) != 0 {
startWk := getNumbers(pts[2])
endWk := getNumbers(pts[3])
if endWk < startWk {
endWk += 7
}
for i := startWk; i <= endWk; i++ {
num := i
if num > 6 {
num -= 7
}
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_WEEK, Value: uint32(num)})
}
} else {
wkNum := getNumbers(pts[2])
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_WEEK, Value: uint32(wkNum)})
}
}
timeParse := pts[4]
var hour uint32
if pts[5] != "" {
hour = uint32(getNumbers(pts[5]))
if timeParse == "下午" || strings.Contains(timeParse, "晚") || strings.Contains(timeParse, "夜") {
hour += 12
}
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_HOUR, Value: hour})
} else if timeParse != "" {
switch timeParse {
case "上午":
hour = 9
case "中午":
hour = 8
case "下午":
hour = 15
case "傍晚":
hour = 18
case "夜里", "晚上", "晚", "夜", "夜晚":
hour = 21
case "凌晨":
hour = 0
case "清晨":
hour = 6
}
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_HOUR, Value: hour})
}
if pts[6] != "" {
if pts[6] == "半" {
pts[6] = "30"
}
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: uint32(getNumbers(pts[6]))})
} else if hour != 0 {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: 0})
}
if pts[7] != "" {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(getNumbers(pts[7]))})
} else if hour != 0 {
rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: 0})
}
count := 1
if pts[1] != "" {
count = 0
}
return startimer.NewTimer(base, startimer.WithRepeats(&rpt), startimer.WithRunCountLimit(count))
}
return startimer.StarTimer{}, errors.New("no Match")
}
func WhenWithPeriod(str string) (startimer.StarTimer, error) {
if match, _ := regexp.MatchString(`(周|星期|礼拜)[一二三四五六天日]`, str); match {
return matchPeroidPattern02(time.Now(), str)
}
return matchPeriodPattern01(time.Now(), str)
}
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
}