• 【正则表达式 】java 正则表达式 校验日期格式


    【正则表达式 】java 正则表达式 校验日期格式

    版权声明:本文为CSDN博主「RanLZ」的原创文章,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/RangeLZ/article/details/127109751

    1 引言

    我们时常会遇到,判断一个String是不是合法的日期格式。当其是一个正确的日期时,我们还需要判断其格式是否符合我们的规范,常见格式如下:

    • yyyyMMdd (20220929)
    • yyyy-MM-dd (2022-09-29)
    • yyyy/MM/dd (2022/09/29)
    • yyyy.MM.dd (2022.09.29)

    对于这些不同的格式来说,其实我们只要确定了年月日,再根据不同的格式来微调我们的正则表达式即可。因此本篇讲解以格式 yyyyMMdd 为例。其他格式不再详解,其正则表达式微调即可得到,这里就不赘述了。

    2 基础知识

    2.1 什么是正确的日期

    MSDN中定义的DateTime对象的有效范围是:0001-01-01 00:00:00到9999-12-31 23:59:59。

    • 因此我们筛选的日期为 0001010199991231 (以格式 yyyyMMdd 为例,后文将不再强调)

    其次,对于日历中大家都知道的 大月小月,这里也不再赘述。

    在小月中有个特殊的 2月 ,它一个月只有28 或 29天,而其具体的天数根据是否为 闰年 来决定。

    2.2 什么是闰年

    我们通过计算方式的不同,将闰年分为 普通闰年世纪闰年

    • 普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。
    • 世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。

    2.3 正则表达式基础

    由于正则表达式的知识比较繁多,这里不做过多的介绍。只对本文将用到的表达式进行讲解。

    字符描述
    |指明两项之间的一个选择,意为
    \d匹配一个数字字符。等价于 [0-9]。
    {n}n 是一个非负整数。匹配确定的 n 次。
    [1-9][1-9] 表示一个区间,匹配1-9的数字
    [ABC]匹配 […] 中的所有字符,例如 [358] 匹配数字 3、5、8

    接下来我们将这些简单的字符进行一个组合,看看你是否还能理解他们的意思呢?

    正则表达式描述举例文本错误文本
    \d{3}3个数字都是0-9的间的数字237、832、129a37、ufo
    \d{3}[1-9]前3个数字都是0-9的间的数字,第四个数字是1-9直接的数字2372、4041、90018720、2020
    [7-9]|[523]该数字要么是7-9之间的一个数,要么是2,3,5其中的一个数字7、5、21、4、6

    简单的学会使用正则表达式了,那我们就开始正式的开始书写吧。

    3 构造正则表达式

    3.1 闰年的情况

    为了方便后面的表示,我们将 yyyy 变为 y1y2y3y4

    3.1.1 世纪闰年的情况
    • 世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。

    世纪闰年 的定义我们可以知道,y3 和 y4 一定是0的,因此可得如下表格:

    y1y2y3y4
    待定待定00

    现在来讨论 y1 和 y2,由定义可知,我们可知 y1y2这个二位数一定是4的倍数。4的倍数的二位数一共有:

    • 04、08、12、16、20、
    • 24、28、32、36、40、
    • 44、48、52、56、60、
    • 64、68、72、76、80、
    • 84、88、92、96、

    相信大家也看出规律了,因此可得如下表格:

    y1y2y1y2y3y4
    0[48]0[48]00
    [2468][48][2468][048]00
    [3579][48][3579][26]00

    可以看到,此时有3种情况,这里我们用 | 将其联系起来成为一条正则表达式,如下:

    ((0[48]|[2468][048]|[3579][26])00)
    
    3.1.2 普通闰年的情况
    • 普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。

    因此在此我们只需要判断,y1y2y3y4 是否为4的倍数即可,但这里也想上面把所有情况列出来找规律吗?这里可是4位数,情况将远远大于2位数的情况。这里我们来找找有没有什么可以减少位数的方法呢?

    ∵ \because y1y2y3y4 = = = y1y200 + y3y4
    ∵ \because y1y200 = 100 ∗ m ( m ∈ N ) = 100 * m(m \in N) =100mmN
    ∴ \therefore y1y2y3y4 = 100 ∗ m = 100 * m =100m + y3y4 ( m ∈ N ) (m \in N) mN
    ∵ 100 = 4 ∗ 25 \because 100 = 4 * 25 100=425
    ∴ 100 为 4 的 倍 数 \therefore 100为4的倍数 1004
    ∴ \therefore y1y200 = 4 ∗ 25 ∗ m ( m ∈ N ) , 为 4 的 倍 数 = 4 * 25 * m(m \in N),为4的倍数 =425mmN4

    所以 y1y200 不管 y1y2 为何值都为4的倍数,可得下表:

    y1y2y1y2y3y4
    \d\d\d{2}待定待定

    而我们可以知道,一个为4的倍数的数,只有加上一个为4的倍数,和才能为4的倍数。故我们现在只需要求 y3y4 为4的情况即可,我们按照之前列举的方法可得如下表:

    y1y2y1y2y3y4
    \d\d\d{2}0[48]
    \d\d\d{2}[2468][48]
    \d\d\d{2}[13579][26]

    这里我们用 | 将其联系起来成为一条正则表达式,如下:

    (\d{2})(0[48]|[2468][048]|[13579][26])
    
    3.1.3 闰年的特殊日期

    我们可以知道闰年的特殊之处在于2月29日 这一天是否存在,其他日子不存在闰年与平年的区别。因此我们只需要在闰年的情况下,判断2月29日这一天的日子即可,故可得以下正则表达式:

    世纪闰年:(\d{2})(0[48]|[2468][048]|[13579][26])0229
    
    普通闰年:((0[48]|[2468][048]|[3579][26])00)0229
    

    用 | 将其联系起来成为一条正则表达式,如下:

    (((\d{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229)
    

    3.2 其他情况

    现在解决了 2月29日 这个棘手的问题,对于其他日子,我们将不在区分闰年。看到这你是不是以为就可以直接 \d{4} 来表示y1y2y3y4 了?

    看来你忽略了一个条件,在 2.2.1 中我们明确了时间的范围为为 0001010199991231 ,但当 y1y2y3y4\d{4} 存在 0000 这个情况,显然这个数据并不在我们合法的范围中。
    因此我们可以得到如下的表:

    y1y2y3y4
    \d\d\d[1-9]
    \d\d[1-9]\d
    \d[1-9]\d\d
    [1-9]\d\d\d

    用 | 将其联系起来成为一条正则表达式,如下:

    (\d{3}[1-9]|\d{2}[1-9]\d|\d[1-9]\d{2}|[1-9]\d{3})
    

    然后就是构造 的正则表达式了

    3.2.1 大月

    首先是大月为:01,03,05,07,08,10,12。
    正则表达式如下:

    (0[13578]|1[02])
    

    大月每月的日子从1日-31日均有。
    正则表达式如下:

    (0[1-9]|[12]\d|3[01])
    

    故大月的正则表达式为:

    ((0[13578]|1[02])(0[1-9]|[12]\d|3[01]))
    
    3.2.2 小月

    首先是小月为:02,04,06,09,11。(但2月的日子和其他小月不同,这里将排除掉2月)
    正则表达式如下:

    (0[469]|11)
    

    小月(不含2月)每月的日子从1日-30日均有。
    正则表达式如下:

    (0[1-9]|[12]\d|30)
    

    故小月(除2月)的正则表达式为:

    (0[469]|11)(0[1-9]|[12]\d|30))
    
    3.2.3 2月

    因为前面我们已经特殊表示了2月29日,所以这里我们只需要考虑2月的1日到28日,正则表达式如下:

    (02(0[1-9]|[1]\d|2[0-8])
    

    3.3 完整表达式

    现在我们将全年的年月日均表达出来了,我们将其用 | 联系起来可得如下正则表达式(不包含2月29日):

    ((\d{3}[1-9]|\d{2}[1-9]\d|\d[1-9]\d{2}|[1-9]\d{3})(((0[13578]|1[02])(0[1-9]|[12]\d|3[01]))|((0[469]|11)(0[1-9]|[12]\d|30))|(02(0[1-9]|[1]\d|2[0-8]))))
    

    4 总结

    经过前面的努力,我们得到了如下的两个表达式:

    闰年2月29日情况:
    (((\d{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229)
    不含2月29日情况:
    ((\d{3}[1-9]|\d{2}[1-9]\d|\d[1-9]\d{2}|[1-9]\d{3})(((0[13578]|1[02])(0[1-9]|[12]\d|3[01]))|((0[469]|11)(0[1-9]|[12]\d|30))|(02(0[1-9]|[1]\d|2[0-8]))))
    

    最终我们将这两个情况,用 | 联系起来,我们就得到了校验日期的正则表达式了!

    ((\d{3}[1-9]|\d{2}[1-9]\d|\d[1-9]\d{2}|[1-9]\d{3})(((0[13578]|1[02])(0[1-9]|[12]\d|3[01]))|((0[469]|11)(0[1-9]|[12]\d|30))|(02(0[1-9]|[1]\d|2[0-8]))))|(((\d{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229)
    
  • 相关阅读:
    webUI自动化之基本框架搭建(python + selenium + unittest)
    select并发服务器实现
    计算机网络:组帧
    3DMAX金属屋顶墙面铺设插件使用方法
    使用flash_download_tool工具烧录esp8266的固件但无法烧录成功
    MAC在网络结构中的位置:深入解析
    spring MVC源码探索之AbstractHandlerMethodMapping
    最快最简单的排序——桶排序
    电商RN项目秒开优化实践
    第42节——路由知识额外扩展
  • 原文地址:https://blog.csdn.net/RangeLZ/article/details/127109751