I need to write an regular expression that matches Cron time expressions, like these ones:
- 28 2 7 1 1
- 28 2 7 1 *
- 28 2 7 * *
- 28 2 * * *
- 28 * * * *
- * * * * *
I need to write an regular expression that matches Cron time expressions, like these ones:
To validate cron expressions in general, it'll depend greatly on the specific implementation you're using
In general, most adhere to the the following format:
Field name | Mandatory? | Allowed values | Special characters |
---|---|---|---|
Seconds | No* | 0-59 | * / , - |
Minutes | Yes | 0-59 | * / , - |
Hours | Yes | 0-23 | * / , - |
Day of month | Yes | 1-31 | * / , - L W |
Month | Yes | 1-12 or JAN-DEC | * / , - |
Day of week | Yes | 0-6 or SUN-SAT | * / , - L # |
Year | No* | 1970–2099 | * / , - |
*where seconds and years are non-standard and sometimes not included
Some flavors allow predefined time periods like this:
Entry | Equivalent to |
---|---|
@annually | 0 0 0 1 1 * * |
@yearly | 0 0 0 1 1 * * |
@monthly | 0 0 0 1 * * * |
@weekly | 0 0 0 * * 0 * |
@daily | 0 0 0 * * * * |
@hourly | 0 0 * * * * * |
@reboot |
Some flavors allow using the @every <duration>
syntax with the following timespan units:
Unit | Definition |
---|---|
ns |
nanosecond |
us , µs |
microsecond |
ms |
millisecond |
s |
second |
m |
minute |
h |
hour |
To validate predefined macros, you can use the following regex:
/@(annually|yearly|monthly|weekly|daily|hourly|reboot)/
Which will pass the following test cases:
@daily
@hourly
@every
RegexTo validate @every
durations, you can use the following regex:
/@every (\d+(ns|us|µs|ms|s|m|h))+/
Which will pass the following test cases:
@every 5s
@every 20h30m
Validating cron terms in the regular expression is a little trickier since there are so many variations.
Just focusing in on a single term, the following are all valid:
,
/
or -
*
To validate a single term, we can use the following regex:
/(\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*/
where \d+
just guarantees you have 1 or more numeric digits
Which will pass the following test cases:
1,2,3
1,2
1/2
1-2
1
*
To check the full expression, we can just make sure we have {5,7}
terms with the following regex:
/(((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7}/
If we wanted to distinguish between each term, we'd need to validate numbers within a certain range:
Allowed values | Regex |
---|---|
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] |
If however, we just want to make sure something looks like a regex expression without worrying about which term is days vs. hours, the expression stays a lot cleaner, so that's what I'll go with for simplicity
By combining the above statements, we can have a relatively simple sanity check that the term looks regex-y with the following expression:
/(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})/
I just finished writing one, so here is mine, hope it helps.
This should allow the * or */num and also limit the number values to their logical range (1-12 for months, 0-24 for hours, and so on)
/^(\*|([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]))$/
Took me a while :D it validates based on this documentation: http://en.wikipedia.org/wiki/Cron However it doesn't take into account that you cannot specify day of week and day of month, ie you can specify both according to this regex. This can be used for 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})$/
Test it at: https://regexr.com/5bdes
Using (?:
for hidding the groups.
^(?:(?:(?:(?:\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 * ?
It's hard to make an exact regex without knowing which program you'll use to run it, but this should work:
(28|\*) (2|\*) (7|\*) (1|\*) (1|\*)
To avoid a very long line, you may split the cron string then match each field with below patterns. Value range, step and comma groups are supported!
// 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]*)?)*$/
It cannot verify the range boudary, i.e. 0,*/3,6-1/20
is acceptable here
A very useful site that might help: https://crontab.guru/
Here's my solution, as I found this question and the answers didn't suit my purpose. This .NET regex conditionally parses a 5-7 part cron statement, includes (afaik) most of the special characters I've seen and will only populate the correct captures (seconds in seconds group, etc) for any length. It also doesn't try to validate the digits of the dates input, ie. you can input the 67th minute, that is more verbose and I simplified for readability. It's also not anchored anywhere and you might need some lazy matching to the end of the line to cleanly capture multiples, but i stripped that out so as not to confuse.
You'll want this as multi-line, ignore whitespace, explicit capture.
((?<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)
@KyleMit answer's is a great place to start, but I found out that his regex is also catching some invalid use-cases like:
So I updated his regex:
/(^((\*\/)?([0-5]?[0-9])((\,|\-|\/)([0-5]?[0-9]))*|\*)\s+((\*\/)?((2[0-3]|1[0-9]|[0-9]|00))((\,|\-|\/)(2[0-3]|1[0-9]|[0-9]|00))*|\*)\s+((\*\/)?([1-9]|[12][0-9]|3[01])((\,|\-|\/)([1-9]|[12][0-9]|3[01]))*|\*)\s+((\*\/)?([1-9]|1[0-2])((\,|\-|\/)([1-9]|1[0-2]))*|\*|(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|des))\s+((\*\/)?[0-6]((\,|\-|\/)[0-6])*|\*|00|(sun|mon|tue|wed|thu|fri|sat))\s*$)|@(annually|yearly|monthly|weekly|daily|hourly|reboot)/
and now it is working as expected.
you can use the following Regular expression and use the test method on your input to check if the input is valid or not.
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-)))*$/
),
It's developed based on the below format: 'second[0-59] minute[0-59] hour[0-23] day-of-month[1-31] month[1-12] day-of-week[0-6]'
For instance, if you use something like *,*/5,5-10 5-6,10-12 20 2 * 3-4
in your input and run the pattern.test(your input variable), you will get true result.
Generally the above regular expression work properly, but if you use bigger number-small number, such as 4-3, the result will get true in the final result which is not acceptable. So, to resolve this issue, you can use the following function too for the onkeyup or onblur attributes of your input and make it equal to the following function name, like "dashCheck" to check this case as well.
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;
}
Now, if you use the regular expression and call the above function both, your cronjob will be perfectly checked and worked.
for the people who wanna validate allowed value
^(((([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))+)
Your current regex will only match 5 characters, since each character class can only match a single character. For each position you either want to match the number or *
, with one or more spaces between each position, you can do that with the following:
(28|\*) +[2*] +[7*] +[1*] +[1*]
Note that since the first number has two digits, you need to use alternation instead of a character class.
You will probably also want to add some anchors to your regex so that it doesn't match just part of a string, if this is necessary add ^
to the beginning and $
to the end.
do the simplest thing that could possibly work
"^28 2 7 1 1$|^28 2 7 1 \*$|^28 2 7 \* \*$|^28 2 \* \* \*$|^28 \* \* \* \*$|^\* \* \* \* \*$"
Not sure if this can help somebody, but here are some regex to check time parameter values without the feature for writing out the names of weekdays.
//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;
}
NO specific number ranges
^(?:(?:(?:\d+-\d+\/\d+|\d+(?:[-,\/]\d+)?|\*\/\d+)(?:,(?:\d+-\d+\/\d+|\d+(?:[-,\/]\d+)?|\*\/\d+))*)|\*)$
^(((?:[1-9]?\d|\*)(\/[0-9]{1,2}){0,1}\s){4}(?:([1-9]?\d|\*)(\/[0-9]{1,2}){0,1}|(MON)|(TUE)|(WED)|(THU)|(FRI)|(SAT)|(SUN))){1}$