Skip to content

Instantly share code, notes, and snippets.

@dkandalov
Last active April 6, 2019 09:30
Show Gist options
  • Save dkandalov/a2aed17cfdeb65243022 to your computer and use it in GitHub Desktop.
Save dkandalov/a2aed17cfdeb65243022 to your computer and use it in GitHub Desktop.
function createCronRegex() {
var regexByField = {};
regexByField["sec"] = "[0-5]?\\\\d";
regexByField["min"] = "[0-5]?\\\\d";
regexByField["hour"] = "[01]?\\\\d|2[0-3]";
regexByField["day"] = "0?[1-9]|[12]\\\\d|3[01]";
regexByField["month"] = "[1-9]|1[012]";
regexByField["dayOfWeek"] = "[0-7]";
regexByField["year"] = "|\\\\d{4}";
["sec", "min", "hour", "day", "month", "dayOfWeek", "year"].forEach(function(field) {
var number = regexByField[field];
var range =
"(?:" + number + ")" +
"(?:" +
"(?:-|/|," + ("dayOfWeek" === field ? "|#" : "") + ")" +
"(?:" + number + ")" +
")?";
if (field === "dayOfWeek") range += "(?:L)?";
if (field === "month") range += "(?:L|W)?";
regexByField[field] = "\\\\?|\\\\*|" + range + "(?:," + range + ")*";
});
var monthValues = "JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC";
var monthRange = "(?:" + monthValues + ")(?:(?:-)(?:" + monthValues + "))?";
regexByField["month"] += "|\\\\?|\\\\*|" + monthRange + "(?:," + monthRange + ")*";
var dayOfWeekValues = "MON|TUE|WED|THU|FRI|SAT|SUN";
var dayOfWeekRange = "(?:" + dayOfWeekValues + ")(?:(?:-)(?:" + dayOfWeekValues + "))?";
regexByField["dayOfWeek"] += "|\\\\?|\\\\*|" + dayOfWeekRange + "(?:," + dayOfWeekRange + ")*";
return '^\\\\s*($' +
'|#' +
'|\\\\w+\\\\s*=' +
"|" +
"(" + regexByField["sec"] + ")\\\\s+" +
"(" + regexByField["min"] + ")\\\\s+" +
"(" + regexByField["hour"] + ")\\\\s+" +
"(" + regexByField["day"] + ")\\\\s+" +
"(" + regexByField["month"] + ")\\\\s+" +
"(" + regexByField["dayOfWeek"] + ")(|\\\\s)+" +
"(" + regexByField["year"] + ")" +
")$";
}
package regex;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static regex.CronRegex.Field.*;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class CronRegex {
@Test public void regression() {
String regex = "^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|/|,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|/|,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|/|,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|/|,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|/|,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|/|,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|/|,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|/|,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|/|,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|/|,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|/|,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|/|,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|/|,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|/|,)(?:|\\d{4}))?)*))$";
System.out.println(regex);
String cronRegex = createCronRegex();
assertThat(cronRegex, equalTo(regex));
}
@Test public void quartzExamples() {
String cronRegex = createCronRegex();
// example from http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
List<String> quartzExamples = asList(
"0 0 12 * * ?",
"0 15 10 ? * *",
"0 15 10 * * ?",
"0 15 10 * * ? *",
"0 15 10 * * ? 2005",
"0 * 14 * * ?",
"0 0/5 14 * * ?",
"0 0/5 14,18 * * ?",
"0 0-5 14 * * ?",
"0 10,44 14 ? 3 WED",
"0 15 10 ? * MON-FRI",
"0 15 10 15 * ?",
// "0 15 10 L * ?", broken
"0 15 10 ? * 6L",
"0 15 10 ? * 6L 2002-2005",
"0 15 10 ? * 6#3",
"0 0 12 1/5 * ?",
"0 11 11 11 11 ?"
);
for (String quartzExample : quartzExamples) {
assertTrue(quartzExample, quartzExample.matches(cronRegex));
}
}
public enum Field {
sec, min, hour, day, month, dayOfWeek, year
}
// originally copied from http://stackoverflow.com/questions/2362985/verifying-a-cron-expression-is-valid-in-java
public static String createCronRegex() {
Map<Field, String> regexByField = new HashMap<Field, String>();
regexByField.put(sec, "[0-5]?\\d");
regexByField.put(min, "[0-5]?\\d");
regexByField.put(hour, "[01]?\\d|2[0-3]");
regexByField.put(day, "0?[1-9]|[12]\\d|3[01]");
regexByField.put(month, "[1-9]|1[012]");
regexByField.put(dayOfWeek, "[0-6]");
regexByField.put(year, "|\\d{4}");
// expand regex to contain different time specifiers
for (Field field : Field.values()) {
String number = regexByField.get(field);
String range =
"(?:" + number + ")" +
"(?:" +
"(?:-|/|," + (dayOfWeek == field ? "|#" : "") + ")" +
"(?:" + number + ")" +
")?";
if (field == dayOfWeek) range += "(?:L)?";
if (field == month) range += "(?:L|W)?";
regexByField.put(field, "\\?|\\*|" + range + "(?:," + range + ")*");
}
// add string specifiers
String monthValues = "JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC";
String monthRange = "(?:" + monthValues + ")(?:(?:-)(?:" + monthValues + "))?";
regexByField.put(month, regexByField.get(month) + "|\\?|\\*|" + monthRange + "(?:," + monthRange + ")*");
String dayOfWeekValues = "MON|TUE|WED|THU|FRI|SAT|SUN";
String dayOfWeekRange = "(?:" + dayOfWeekValues + ")(?:(?:-)(?:" + dayOfWeekValues + "))?";
regexByField.put(dayOfWeek, regexByField.get(dayOfWeek) + "|\\?|\\*|" + dayOfWeekRange + "(?:," + dayOfWeekRange + ")*");
return "^\\s*($" +
"|#" +
"|\\w+\\s*=" +
"|" +
"(" + regexByField.get(sec) + ")\\s+" +
"(" + regexByField.get(min) + ")\\s+" +
"(" + regexByField.get(hour) + ")\\s+" +
"(" + regexByField.get(day) + ")\\s+" +
"(" + regexByField.get(month) + ")\\s+" +
"(" + regexByField.get(dayOfWeek) + ")(|\\s)+" +
"(" + regexByField.get(year) + ")" +
")$";
}
}
@KissBalazs
Copy link

I think the 4 ''-s are unnecessary in the JS code, you only need two of each.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment