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,只提供一个匹配方法
下面逐步介绍实现,构建一个完整解决方案
3.1 匹配数字
创建一个简单的正则来对字符串进行格式约束:
这里我们指定了一个有效日期必须由三组中划线分割的整数组成,第一组由 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}),通过匹配一个以 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 匹配一组闰年,在 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
举例:匹配的日期: 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 天
举例:匹配的日期: 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 天
举例:匹配的月份: 2018-04-30, 2019-06-30, 2020-09-30
不匹配的月份: 2018-04-31, 2019-06-31, 2018/04/30
3.7 汇总的日期匹配器
现在我们将上面的所有模式合并成一个匹配器满足所有的日期约束
我们使用了"|"来匹配 28 天的、29 天的、30 天的、31 天的,此时我们已经满足了开始介绍的日期的所有约束
3.8 性能说明
解析复杂的表达式可能会影响性能。本文的主要目的主要是了解用正则来判断日期的一种思路,如果要一种可靠且快速的方法来验证日期,请考虑使用 Java8 提供的 LocalDate.parse()。
四、总结
本文我们学习了使用正则表达式从格式、范围和月份长度等规则匹配公历日期。
版权声明: 本文为 InfoQ 作者【okokabcd】的原创文章。
原文链接:【http://xie.infoq.cn/article/076ef4b5aa54c83118b890e7e】。文章转载请联系作者。
评论