代码之家  ›  专栏  ›  技术社区  ›  Omar Kooheji

验证cron表达式在Java中是否有效

  •  23
  • Omar Kooheji  · 技术社区  · 15 年前

    我正在使用Quartz用Java编写一个调度应用程序。我使用的是CronTrigger,但我的cron表达式是在调度之前输入数据库的,并且基于用户输入。

    当我捕获cron表达式时,有没有办法验证它们是否有效?我宁愿这样做,并给用户一个适当的错误消息,而不是等到调度程序运行并且在尝试创建触发器时得到ParseException。这可能是用户输入数据后的几天。

    4 回复  |  直到 13 年前
        1
  •  59
  •   sfussenegger    15 年前

    你不能简单地创建一个触发器而不执行它吗?如果出现异常,您可以给出适当的反馈。如果表达式正常,则将表达式持久化到DB。

    编辑:或只需执行以下操作:

    org.quartz.CronExpression.isValidExpression(expression);
    
        2
  •  18
  •   Community CDub    8 年前

    我修改了以下内容 code

    ^\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}))?)*))$
    

    以下是java代码:

    private static String cronRegex = null;
    
    public static String getCronRegex()
    {
      if (cronRegex == null)
      {
        // numbers intervals and regex
        Map<String, String> numbers = new HashMap<String, String>();
        numbers.put("sec", "[0-5]?\\d");
        numbers.put("min", "[0-5]?\\d");
        numbers.put("hour", "[01]?\\d|2[0-3]");
        numbers.put("day", "0?[1-9]|[12]\\d|3[01]");
        numbers.put("month", "[1-9]|1[012]");
        numbers.put("dow", "[0-6]");
        numbers.put("year", "|\\d{4}");
    
        Map<String, String> field_re = new HashMap<String, String>();
    
        // expand regex to contain different time specifiers
        for (String field : numbers.keySet())
        {
          String number = numbers.get(field);
          String range = "(?:" + number + ")(?:(?:-|\\/|\\," +  ("dow".equals(field)? "|#" :    "") + 
    
            ")(?:" + number + "))?" +  ("dow".equals(field)? "(?:L)?" : ("month".equals(field)? "(?:L|W)?" : ""));
          field_re.put(field, "\\?|\\*|" + range + "(?:," + range + ")*");
        }
    
        // add string specifiers
        String monthRE = field_re.get("month");
        String monthREVal =   "JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC";
        String monthRERange = "(?:" + monthREVal + ")(?:(?:-)(?:" + monthREVal + "))?" ; 
        monthRE = monthRE +  "|\\?|\\*|" + monthRERange + "(?:," + monthRERange + ")*" ;
        field_re.put("month", monthRE);
    
        String dowRE = field_re.get("dow");
        String dowREVal = "MON|TUE|WED|THU|FRI|SAT|SUN";
        String dowRERange = "(?:" + dowREVal + ")(?:(?:-)(?:" + dowREVal + "))?" ;
    
        dowRE = dowRE + "|\\?|\\*|" + dowRERange + "(?:," + dowRERange + ")*" ;
        field_re.put("dow", dowRE);
    
        StringBuilder fieldsReSB = new StringBuilder();
        fieldsReSB.append("^\\s*(").append("$") //
          .append("|#") //
          .append("|\\w+\\s*=") //
          .append("|") //
          .append("(")//
          .append(field_re.get("sec")).append(")\\s+(")//
          .append(field_re.get("min")).append(")\\s+(")//
          .append(field_re.get("hour")).append(")\\s+(")//
          .append(field_re.get("day")).append(")\\s+(")//
          .append(field_re.get("month")).append(")\\s+(")//
          .append(field_re.get("dow")).append(")(|\\s)+(")//
          .append(field_re.get("year"))//
          .append(")")//
          .append(")")//
          .append("$");
    
        cronRegex = fieldsReSB.toString();
      }
      return cronRegex;
    }
    

    documentation

        3
  •  6
  •   sashimi    7 年前

    你可以用 cron-utils 您不仅可以检查cron是否有效,还可以将不同的cron格式转换为目标cron格式(例如:如果用户输入一个Unix cron表达式,您可以轻松地转换为Quartz并将其持久化为DB)。

    // Turn cron expressions into another format by using CronMapper:
    CronMapper cronMapper = CronMapper.fromUnixToQuartz();
    
    Cron quartzCron = cronMapper.map(unixCron);
    // and to get a String representation of it, we can use
    quartzCron.asString();
    
    //validate the cron expression!
    quartzCron.validate()
    
        4
  •  0
  •   jovanchohan    8 年前

    我在Github上的“QuartzNet”项目中发现了以下正则表达式。我认为这可能是Quartz用来验证cron表达式的方法。

    链接: https://github.com/quartznet/quartznet/blob/master/src/Quartz/Xml/job_scheduling_data_2_0.xsd

    (((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\?])|([\*]))[\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\?])|([\*]))[\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\?])|([\*]))[\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\?])|([\*]))[\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((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))?)|((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]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((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))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\?])|([\*]))([\s]?(([\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?| (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?| ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?)
    
        5
  •  0
  •   LHCHIN    5 年前

    如果您正在使用 org.quartz ,您可以按如下方式验证Cron表达式:

    try {
        CronExpression cron = new CronExpression(cronExpression);
        ...
    } catch (ParseException e) {
        //exception handling
    }
    

    Class CronExpression :

    公共CronExpression(字符串CronExpression) 抛出解析异常

    参数:
    cronExpression—新对象应表示的cron表达式的字符串表示形式
    抛出:

        6
  •  0
  •   车言涛    4 年前

    如果没有org.quartz包,还可以使用org.springframework.scheduling.support.CronSequenceGenerator.isValidExpression(@Nullable String expression)方法。