我需要编写一个与Cron 时间表达式匹配的正则表达式,例如:
- 28 2 7 1 1
- 28 2 7 1 *
- 28 2 7 * *
- 28 2 * * *
- 28 * * * *
- * * * * *
我需要编写一个与Cron 时间表达式匹配的正则表达式,例如:
要验证一般的cron 表达式,很大程度上取决于您使用的具体实现
一般来说,大多数遵循以下格式:
字段名称 | 强制的? | 允许值 | 特殊的角色 |
---|---|---|---|
秒 | 不* | 0-59 | * / , - |
分钟 | 是的 | 0-59 | * / , - |
小时 | 是的 | 0-23 | * / , - |
一个月中的哪一天 | 是的 | 1-31 | * / , - L W |
月 | 是的 | 1-12 或 1-12 月 | * / , - |
星期几 | 是的 | 0-6 或 SUN-SAT | * / , - L # |
年 | 不* | 1970–2099 | * / , - |
*其中秒和年是非标准的,有时不包括在内
一些风格允许像这样的预定义时间段:
入口 | 相当于 |
---|---|
@每年 | 0 0 0 1 1 * * |
@每年 | 0 0 0 1 1 * * |
@月刊 | 0 0 0 1 * * * |
@每周 | 0 0 0 * * 0 * |
@日常 | 0 0 0 * * * * |
@hourly | 0 0 * * * * * |
@重启 |
一些风格允许使用@every <duration>
具有以下时间跨度单位的语法:
单元 | 定义 |
---|---|
ns |
纳秒 |
us ,µs |
微秒 |
ms |
毫秒 |
s |
第二 |
m |
分钟 |
h |
小时 |
要验证预定义的宏,您可以使用以下正则表达式:
/@(annually|yearly|monthly|weekly|daily|hourly|reboot)/
它将通过以下测试用例:
@daily
@hourly
@every
正则表达式要验证@every
持续时间,您可以使用以下正则表达式:
/@every (\d+(ns|us|µs|ms|s|m|h))+/
它将通过以下测试用例:
@every 5s
@every 20h30m
在正则表达式中验证 cron 术语有点棘手,因为有很多变体。
只关注一个术语,以下都是有效的:
,
/
或分隔-
*
要验证单个术语,我们可以使用以下正则表达式:
/(\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*/
只保证你有\d+
1 个或多个数字
它将通过以下测试用例:
1,2,3
1,2
1/2
1-2
1
*
要检查完整的表达式,我们可以确保我们有{5,7}
以下正则表达式:
/(((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7}/
如果我们想区分每个术语,我们需要验证一定范围内的数字:
允许值 | 正则表达式 |
---|---|
0-59 | [1-5]?[0-9] |
0-23 | 2[0-3]|1[0-9]|[0-9] |
1-31 | 3[01]|[12][0-9]|[1-9] |
1-12 | 1[0-2]|[1-9] |
0-6 | [0-6] |
1970–2099 | 19[7-9][0-9]|20[0-9][0-9] |
但是,如果我们只是想确保某些东西看起来像一个正则表达式,而不用担心哪个术语是天与小时,那么表达式会保持得更清晰,所以为了简单起见,这就是我要使用的
通过结合上述语句,我们可以使用以下表达式进行一个相对简单的完整性检查,即该术语看起来是 regex-y :
/(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})/
刚写完,就写到这里,希望对你有帮助。
这应该允许 * 或 */num 并且还将数值限制在它们的逻辑范围内(1-12 个月,0-24 小时,等等)
/^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$/
花了我一段时间:D 它根据以下文档进行验证:http ://en.wikipedia.org/wiki/Cron 但是它没有考虑到您不能指定星期几和月份中的某一天,即您可以指定两者都根据这个正则表达式。这可以用于 boost::regex
(((([*])|(((([0-5])?[0-9])((-(([0-5])?[0-9])))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))(,(((([*])|(((([0-5])?[0-9])((-(([0-5])?[0-9])))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?)))* (((([*])|(((((([0-1])?[0-9]))|(([2][0-3])))((-(((([0-1])?[0-9]))|(([2][0-3])))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))(,(((([*])|(((((([0-1])?[0-9]))|(([2][0-3])))((-(((([0-1])?[0-9]))|(([2][0-3])))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?)))* (((((((([*])|(((((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))((-(((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))|(L)|(((((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))W))))(,(((((([*])|(((((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))((-(((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))|(L)|(((((([1-2])?[0-9]))|(([3][0-1]))|(([1-9])))W)))))*)|([?])) (((([*])|((((([1-9]))|(([1][0-2])))((-((([1-9]))|(([1][0-2])))))?))|((((JAN)|(FEB)|(MAR)|(APR)|(MAY)|(JUN)|(JUL)|(AUG)|(SEP)|(OKT)|(NOV)|(DEC))((-((JAN)|(FEB)|(MAR)|(APR)|(MAY)|(JUN)|(JUL)|(AUG)|(SEP)|(OKT)|(NOV)|(DEC))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))(,(((([*])|((((([1-9]))|(([1][0-2])))((-((([1-9]))|(([1][0-2])))))?))|((((JAN)|(FEB)|(MAR)|(APR)|(MAY)|(JUN)|(JUL)|(AUG)|(SEP)|(OKT)|(NOV)|(DEC))((-((JAN)|(FEB)|(MAR)|(APR)|(MAY)|(JUN)|(JUL)|(AUG)|(SEP)|(OKT)|(NOV)|(DEC))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?)))* (((((((([*])|((([0-6])((-([0-6])))?))|((((SUN)|(MON)|(TUE)|(WED)|(THU)|(FRI)|(SAT))((-((SUN)|(MON)|(TUE)|(WED)|(THU)|(FRI)|(SAT))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))|((([0-6])L))|(W)|(([#][1-5]))))(,(((((([*])|((([0-6])((-([0-6])))?))|((((SUN)|(MON)|(TUE)|(WED)|(THU)|(FRI)|(SAT))((-((SUN)|(MON)|(TUE)|(WED)|(THU)|(FRI)|(SAT))))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))|((([0-6])L))|(W)|(([#][1-5])))))*)|([?]))((( (((([*])|((([1-2][0-9][0-9][0-9])((-([1-2][0-9][0-9][0-9])))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?))(,(((([*])|((([1-2][0-9][0-9][0-9])((-([1-2][0-9][0-9][0-9])))?)))((/(([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?([0-9])?[0-9])))?)))*))?)
/^((((\d+,)+\d+|(\d+(\/|-|#)\d+)|\d+L?|\*(\/\d+)?|L(-\d+)?|\?|[A-Z]{3}(-[A-Z]{3})?) ?){5,7})$/
在以下位置进行测试:https ://regexr.com/5bdes
用于(?:
隐藏组。
^(?:(?:(?:(?:\d+,)+\d+|(?:\d+(?:\/|-|#)\d+)|\d+L?|\*(?:\/\d+)?|L(?:-\d+)?|\?|[A-Z]{3}(?:-[A-Z]{3})?) ?){5,7})$
/^((((\d+,)+\d+|(\d+(\/|-|#)\d+)|\d+L?|\*(\/\d+)?|L(-\d+)?|\?|[A-Z]{3}(-[A-Z]{3})?) ?){5,7})$|(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)/
# At 12:00 pm (noon) every day during the year 2017:
0 0 12 * * ? 2017
# Every 5 minutes starting at 1 pm and ending on 1:55 pm and then starting at 6 pm and ending at 6:55 pm, every day:
0 0/5 13,18 * * ?
# Every minute starting at 1 pm and ending on 1:05 pm, every day:
0 0-5 13 * * ?
# At 1:15 pm and 1:45 pm every Tuesday in the month of June:
0 15,45 13 ? 6 Tue
# At 9:30 am every Monday, Tuesday, Wednesday, Thursday, and Friday:
0 30 9 ? * MON-FRI
# At 9:30 am on 15th day of every month:
0 30 9 15 * ?
# At 6 pm on the last day of every month:
0 0 18 L * ?
# At 6 pm on the 3rd to last day of every month:
0 0 18 L-3 * ?
# At 10:30 am on the last Thursday of every month:
0 30 10 ? * 5L
# At 6 pm on the last Friday of every month during the years 2015, 2016 and 2017:
0 0 18 ? * 6L 2015-2017
# At 10 am on the third Monday of every month:
0 0 10 ? * 2#3
# At 12 am midnight on every day for five days starting on the 10th day of the month:
0 0 0 10/5 * ?
如果不知道您将使用哪个程序来运行它,很难制作一个精确的正则表达式,但这应该可以:
(28|\*) (2|\*) (7|\*) (1|\*) (1|\*)
为了避免很长的行,您可以拆分 cron 字符串,然后将每个字段与以下模式匹配。支持值范围、步长和逗号组!
// minute: 0-59
/^(\*|[1-5]?[0-9](-[1-5]?[0-9])?)(\/[1-9][0-9]*)?(,(\*|[1-5]?[0-9](-[1-5]?[0-9])?)(\/[1-9][0-9]*)?)*$/
// hour: 0-23
/^(\*|(1?[0-9]|2[0-3])(-(1?[0-9]|2[0-3]))?)(\/[1-9][0-9]*)?(,(\*|(1?[0-9]|2[0-3])(-(1?[0-9]|2[0-3]))?)(\/[1-9][0-9]*)?)*$/
// monthDay: 1-31
/^(\*|([1-9]|[1-2][0-9]?|3[0-1])(-([1-9]|[1-2][0-9]?|3[0-1]))?)(\/[1-9][0-9]*)?(,(\*|([1-9]|[1-2][0-9]?|3[0-1])(-([1-9]|[1-2][0-9]?|3[0-1]))?)(\/[1-9][0-9]*)?)*$/
// month: 1-12
/^(\*|([1-9]|1[0-2]?)(-([1-9]|1[0-2]?))?)(\/[1-9][0-9]*)?(,(\*|([1-9]|1[0-2]?)(-([1-9]|1[0-2]?))?)(\/[1-9][0-9]*)?)*$/
// weekDay: 0-6
/^(\*|[0-6](-[0-6])?)(\/[1-9][0-9]*)?(,(\*|[0-6](-[0-6])?)(\/[1-9][0-9]*)?)*$/
它无法验证范围边界,即0,*/3,6-1/20
在这里可以接受
一个非常有用的网站,可能会有所帮助:https ://crontab.guru/
这是我的解决方案,因为我发现了这个问题并且答案不符合我的目的。这个 .NET 正则表达式有条件地解析一个 5-7 部分的 cron 语句,包括(afaik)我见过的大多数特殊字符,并且只会填充任何长度的正确捕获(秒组等)。它也不会尝试验证日期输入的数字,即。您可以输入第 67 分钟,这更详细,为了便于阅读,我进行了简化。它也没有锚定在任何地方,您可能需要在行尾进行一些惰性匹配以干净地捕获倍数,但我将其剥离以免混淆。
你会希望这是多行,忽略空格,显式捕获。
((?<seconds>\*|([0-5]?[0-9])((-|,|\/)?([0-5]?[0-9])?)+)[ \t]+)?(?#seconds)
(?<minutes>\*|([0-5]?[0-9])((-|,|\/)?([0-5]?[0-9])?)+)[ \t]+(?#minutes)
(?<hours>\*|([0-2]?[0-9])((-|,|\/)?([0-2]?[0-9])?)+)[ \t]+(?#hours)
(?<dom>\*|\?|L|([1-2]?[0-9])((-|,|\/)?([1-2]?[0-9])?)+)\s(?#dayofmonth)
(?<month>((\*)|(1?[0-9])|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))((\/|,|-|\#)((\*)|(1?[0-9])|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)))?)\s(?#month)
(?<dow>(\*|\?|L|(MON|TUE|WED|THU|FRI|SAT|SUN)|[1-7])((-|,|\/|L|W|C|\#)?((MON|TUE|WED|THU|FRI|SAT|SUN)|[1-7])?)+)\s(?#day of week)
(?(seconds)(?<year>([1-2][0-9]{3})((,|-|\/)([1-2][0-9]{3}))?)?)(?#year, cond on seconds match)
您可以使用以下正则表达式并在输入上使用测试方法来检查输入是否有效。
pattern: new RegExp(
/^((\*(?!(-))|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]))|([,]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])(?!(-))))(?!(-\d-)))* ((\*(?!(-))|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]))|([,]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])(?!(-))))(?!(-\d-)))* ((\*(?!(-))|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-3]))|([,]{1}(\*(?!(-))|[0-9]|1[0-9]|2[0-3]|\*\/([0-9]|1[0-9]|2[0-3])(?!(-))))(?!(-\d-)))* ((\*(?!(-))|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[1-9]|1[0-9]|2[0-9]|3[0-1]))|([,]{1}(\*(?!(-))|[1-9]|1[0-9]|2[0-9]|3[0-1]|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])(?!(-))))(?!(-\d-)))* ((\*(?!(-))|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[1-9]|1[0-2]))|([,]{1}(\*(?!(-))|[1-9]|1[0-2]|\*\/([1-9]|1[0-2])(?!(-))))(?!(-\d-)))* ((\*(?!(-))|([0-6])|\*\/([0-6])(?!(-)))(?!(-\d-)))(([-]{1}(\*(?!(-))|[0-6]))|([,]{1}(\*(?!(-))|[0-6]|\*\/([0-6])(?!(-))))(?!(-\d-)))*$/
),
它是基于以下格式开发的:'second[0-59] minute[0-59] hour[0-23] day-of-month[1-31] month[1-12] day-of-week[0 -6]'
例如,如果您*,*/5,5-10 5-6,10-12 20 2 * 3-4
在输入中使用类似的东西并运行 pattern.test(您的输入变量),您将得到真实的结果。
上面的正则表达式一般都可以正常工作,但是如果你用大数-小数,比如4-3,最终的结果会为真,这是不可接受的。因此,要解决此问题,您也可以对输入的 onkeyup 或 onblur 属性使用以下函数,并使其等于以下函数名称,例如“dashCheck”来检查这种情况。
dashCheck() {
let dashNumber = 0;
let text = your input name.pattern;
if (text.match(/-/g)) {
dashNumber = text.match(/-/g).length;
}
let x = -1;
for (let i = 0; i < dashNumber; ++i) {
x = text.indexOf("-", x + 1);
if (isNaN(text[x + 2]) === false && text[x + 2] !== " ") {
if (isNaN(text[x - 2]) === false) {
if (text.slice(x + 1, x + 3) >= text.slice(x - 2, x)) {
} else {
return false;
}
} else {
}
} else if (isNaN(text[x + 1]) === false) {
if (isNaN(text[x - 2]) === false && text[x - 2] !== " ") {
return false;
} else {
if (text.slice(x + 1, x + 2) >= text.slice(x - 1, x)) {
} else {
return false;
}
}
}
}
return true;
}
现在,如果您使用正则表达式并同时调用上述函数,您的 cronjob 将被完美地检查和工作。
您当前的正则表达式只能匹配 5 个字符,因为每个字符类只能匹配一个字符。对于您想要匹配数字或*
的每个位置,每个位置之间有一个或多个空格,您可以使用以下方法来做到这一点:
(28|\*) +[2*] +[7*] +[1*] +[1*]
请注意,由于第一个数字有两位数,因此您需要使用交替而不是字符类。
您可能还想在您的正则表达式中添加一些锚点,以便它不只匹配字符串的一部分,如果有必要添加^
到开头和$
结尾。
做可能可行的最简单的事情
"^28 2 7 1 1$|^28 2 7 1 \*$|^28 2 7 \* \*$|^28 2 \* \* \*$|^28 \* \* \* \*$|^\* \* \* \* \*$"
不确定这是否可以帮助某人,但这里有一些正则表达式来检查时间参数值,而没有写出工作日名称的功能。
//string validation
function allowed_characters($value, $mode){
switch ($mode) {
case '0': //0-59
$preg_code = "^(((([0-5]?[0-9]|60)(-([0-5]?[0-9]|60)){0,1}?)|\*)(,([0-5]?[0-9]|60)((-([0-5]?[0-9]|60)){0,1}?))*?)$";
break;
case '1': //0-23
$preg_code = "^(((([0-1]?[0-9]|2[0-4])(-([0-1]?[0-9]|2[0-4])){0,1}?)|\*)(,([0-1]?[0-9]|2[0-4])((-([0-1]?[0-9]|2[0-4])){0,1}?))*?)$";
break;
case '2': //1-31
$preg_code = "^(((([0-2]?[0-9]|3[0-1])(-([0-2]?[0-9]|3[0-1])){0,1}?)|\*)(,([0-2]?[0-9]|3[0-1])((-([0-2]?[0-9]|3[0-1])){0,1}?))*?)$";
break;
case '3': //0-12
$preg_code = "^(((([0]?[0-9]|1[0-2])(-([0]?[0-9]|1[0-2])){0,1}?)|\*)(,([0]?[0-9]|1[0-2])((-([0]?[0-9]|1[0-2])){0,1}?))*?)$";
break;
case '4': //0-6
$preg_code = "^(((([0]?[[0-7])(-([0]?[0-7])){0,1}?)|\*)(,([0]?[0-7])((-([0]?[0-7])){0,1}?))*?)$";
break;
default:
return false;
break;
}
没有特定的数字范围
^(?:(?:(?:\d+-\d+\/\d+|\d+(?:[-,\/]\d+)?|\*\/\d+)(?:,(?:\d+-\d+\/\d+|\d+(?:[-,\/]\d+)?|\*\/\d+))*)|\*)$
@KyleMit answer's 是一个很好的起点,但我发现他的正则表达式也捕获了一些无效的用例,例如:
所以我更新了他的正则表达式:
/(^((\*\/)?([1-5]?[0-9])((\,|\-|\/)\d+)*|\*)\s((\*\/)?((2[0-3]|1[0-9]|[0-9]))((\,|\-|\/)\d+)*|\*)\s((\*\/)?([1-9]|[12][0-9]|3[01])((\,|\-|\/)\d+)*|\*)\s((\*\/)?([1-9]|1[0-2])((\,|\-|\/)\d+)*|\*)\s((\*\/)?[0-6]((\,|\-|\/)\d+)*|\*)$)|@(annually|yearly|monthly|weekly|daily|hourly|reboot)/
现在它按预期工作。
对于想要验证允许值的人
^(((([1-5]?[0-9],)+[1-5]?[0-9]|([1-5]?[0-9](\/|-)[1-5]?[0-9](\/\d+)?)|[1-5]?[0-9]|\*(\/\d+)?) )((([1-5]?[0-9],)+[1-5]?[0-9]|([1-5]?[0-9](\/|-)[1-5]?[0-9](\/\d+)?)|[1-5]?[0-9]|\*(\/\d+)?) )((((2[0-3]|1[0-9]|[0-9]),)+(2[0-3]|1[0-9]|[0-9])|((2[0-3]|1[0-9]|[0-9])(\/|-)(2[0-3]|1[0-9]|[0-9])(\/\d+)?)|(2[0-3]|1[0-9]|[0-9])|\*(\/\d+)?) )((((3[01]|[12][0-9]|[1-9]),)+(3[01]|[12][0-9]|[1-9])|((3[01]|[12][0-9]|[1-9])(\/|-)(3[01]|[12][0-9]|[1-9])(\/\d+)?)|(3[01]|[12][0-9]|[1-9])|\*(\/\d+)?) )((((1[0-2]|[1-9]),)+(3[01]|[12][0-9]|[1-9])|((1[0-2]|[1-9])(\/|-)(1[0-2]|[1-9])(\/\d+)?)|(1[0-2]|[1-9])|[A-Z]{3}|\*(\/\d+)?) )((([0-6],)+[0-6]|([0-6](\/|-)[0-6]((\/|-)\d+)?)|[0-6]|\*(\/\d+)?|[A-Z]{3}?)))$|(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)