• Java中使用正则检查有效日期


    一、介绍

    正则表达式可用于匹配各种模式,本文将用java中的正则来检测给定字符串是否饮包含有效日期

    二、日期格式概述

    先对公历中一个有效日期做一个定义,日期格式我们一般定义为yyyy-MM-dd。考虑范围大小年、闰年等情况,先说闰年。
    普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。
    世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。
    有效日期举例:

    • 2017-12-31
    • 2020-02-29
    • 2400-02-29

    无效日期举例

    • 2017/12/31: 分割符不正确
    • 2018-1-1: 没有前导0
    • 2018-04-31: 天数不正确
    • 2100-02-29: 平年2月只有28天

    三、实现

    我们要用正则匹配日期,首先先定义一个接口DateMatcher,只提供一个匹配方法

    public interface DateMatcher {
        boolean matches(String date);
    }
    

    下面逐步介绍实现,构建一个完整解决方案

    3.1 匹配数字

    创建一个简单的正则来对字符串进行格式约束:

    public class FormattedDateMatcher implements DateMatcher {
        private static final Pattern DATE_PATTERN = 
            Pattern.compile("^\\d{2}-\\d{4}-\\d{2}$");
    
        @Override
        public boolean matches(String date) {
            return DATE_PATTERN.matcher(date).matches();
        }
    }
    

    这里我们指定了一个有效日期必须由三组中划线分割的整数组成,第一组由4个整数,其余两组各有两个整数。
    举例:
    匹配的日期: 2017-12-31, 2018-01-31, 0000-00-00, 1029-00-72
    不匹配的日期:2018-01, 2018-01-XX, 2020/02/09

    3.2 匹配日期的范围

    现在我们成功匹配了一般日期格式,现在我们做进一步约束,我们将年份限定在1900-2999,月份和日期也做同样的约束

    ^((19|2[0-9])[0-9]{2})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$
    

    这里我们对三组整数范围做了约束

    • ((19|2[0-9])[0-9]{2}),通过匹配一个以19开头或2X开头后跟几个任意数字的数字来覆盖年份的范围
    • (0[1-9]|1[012]),匹配01-12范围内的月份
    • (0[1-9]|[12][0-9]|3[01]),匹配01-31范围内的天数

    匹配的日期:1900-01-01,2205-02-31,2999-12-31
    不匹配的日期:1989-12-31,2018-05-35,2018-13-05,3000-01-01,2018-01-XX

    3.3 匹配2月29

    为了匹配2月29,首先要判断闰年,把1900-2099之间的闰年匹配出来。如果一个数的后2位能被4整除则原数也能被4整除;如果后两位是00,这个数能被100整除

    ^((2000|2400|2800|(19|2[0-9])(0[48]|[2468][048]|[13579][26]))-02-29)$
    

    这个正则由以下部分组成

    • 2000|2400|2800 匹配一组闰年,在1900-2999的范围内,匹配能被400整除的
    • 19|20-9 匹配能被4整除不能被100整除的
    • 02-29 匹配2月29

    举例
    匹配的日期:2020-02-29,2024-02-29,2400-02-29
    不匹配的日期:2019-02-29,2100-02-29,3200-02-29,2020/02/29

    3.4 匹配2月28

    2月29是闰年,我们还要匹配平年的2月28

    ^(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))$
    

    举例:
    匹配的日期: 2018-02-01, 2019-02-13, 2020-02-25
    不匹配的日期: 2000-02-30, 2400-02-62, 2018/02/28

    3.5. Matching 31-Day Months

    3.5 匹配31天的月份

    1、3、5、7、8、10、12月份每月31天

    ^(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))$
    

    举例:
    匹配的日期: 2018-01-31, 2021-07-31, 2022-08-31
    不匹配的日期: 2018-01-32, 2019-03-64, 2018/01/31

    3.6 匹配30天的月份

    4、6、9、11每月30天

    ^(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30))$
    

    举例:
    匹配的月份: 2018-04-30, 2019-06-30, 2020-09-30

    不匹配的月份: 2018-04-31, 2019-06-31, 2018/04/30

    3.7 汇总的日期匹配器

    现在我们将上面的所有模式合并成一个匹配器满足所有的日期约束

    class GregorianDateMatcher implements DateMatcher {
    
        private static Pattern DATE_PATTERN = Pattern.compile(
          "^((2000|2400|2800|(19|2[0-9])(0[48]|[2468][048]|[13579][26]))-02-29)$" 
          + "|^(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))$"
          + "|^(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))$" 
          + "|^(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30))$");
    
        @Override
        public boolean matches(String date) {
            return DATE_PATTERN.matcher(date).matches();
        }
    }
    

    我们使用了"|"来匹配28天的、29天的、30天的、31天的,此时我们已经满足了开始介绍的日期的所有约束

    3.8 性能说明

    解析复杂的表达式可能会影响性能。本文的主要目的主要是了解用正则来判断日期的一种思路,如果要一种可靠且快速的方法来验证日期,请考虑使用Java8提供的LocalDate.parse()。

    四、总结

    本文我们学习了使用正则表达式从格式、范围和月份长度等规则匹配公历日期。

  • 相关阅读:
    jquery
    模板库
    Luogu P1902 刺杀大使
    8.20模拟赛再次观光记
    Luogu P1122 最大子树和
    Luogu P1470 最长前缀 Longest Prefix
    8.18爆炸记
    Luogu P1388 算式
    Luogu P1103 书本整理
    8.17
  • 原文地址:https://www.cnblogs.com/okokabcd/p/16407130.html
Copyright © 2020-2023  润新知