Java最高

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>查看课程

1.介绍

如果使用得当,正则表达式是匹配各种模式的强大工具。

在本文中,我们将使用java.util.regex.包确定是否给定细绳包含有效日期。

有关常规表达式的介绍,请参阅我们的Java正则表达式指南API

2.日期格式概述

我们将定义与国际GREGorian日历有关的有效日期。我们的格式将遵循常规模式:yyyy-mm-dd。

让我们还包括一个概念飞跃有2月29日一天的一年。根据格里高利历,我们称之为一年飞跃如果年号可以被整除4.除了那些被剥夺的人One hundred.但包括那些被剥夺的人400

在所有其他情况下我们会打电话给一年常规的

有效日期的例子:

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

无效日期的例子:

  • 2017/12/31:不正确的标记分隔符
  • 2018-1-1:缺少领先的零
  • 2018-04-31四月的日子算错了
  • 2100-02-29:今年不是跳跃,因为价值划分One hundred.如此,2月份仅限28天

3.实施解决方案

由于我们将使用正则表达式匹配日期,因此让我们首先勾出一个接口DateMatcher,它提供单个匹配方法:

公共接口扩展程序{布尔匹匹配(字符串日期);}

我们将在下面一步一步地介绍实现过程,最终构建完整的解决方案。

3.1。匹配广泛的格式

我们先创建一个非常简单的原型来处理匹配器的格式约束:

class formatteddatematcher实现扩展程序{私有静态模式date_pattern = pattern.compile(“^ \\ d {4}  -  \\ d {2}  -  \\ d {2} $”);@Override public boolean matches(String date) {return DATE_PATTERN.matcher(date).matches();}}

这里我们指定了它有效日期必须包含由短划线分隔的三组整数。第一个组由四个整数组成,其余两组具有两个整数。

匹配日期:2017-12-312018-01-310000-00-001029-99-72.

非匹配日期:2018-012018-01-xx.2020/02/29

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-012205-02-312999-12-31.

非匹配日期:1899-12-31.2018-05-352018-13-053000-01-01.2018-01-xx.

3.3。匹配2月29日

为了正确匹配闰年,我们必须首先确定我们什么时候遇到了闰年,然后确保我们接受2月29日作为这些年的有效日期。

随着我们限制范围的闰年的数量足够大,我们应该使用适当的可分居规则来过滤它们:

  • 如果由数字中的最后两位数字形成的数字可被4可分开4,则原始号码可分解为4
  • 如果这个数的后两位是00,这个数能被100整除

这是一个解决方案:

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

该模式由以下部分组成:

  • 2000 | 2400 | 2800匹配一系列闰年用分频器400在限制范围内1900 - 2999
  • 19 | 2 [0-9](0 [48] | [2468] | [13579] | [26]))匹配所有白名单年的组合,有一个除法4.并且没有分隔件One hundred.
  • -02-29匹配2月2日

匹配日期:2020-02-292024-02-292400-02-29

非匹配日期:2019-02-292100-02-293200-02-292020/02/29

3.4。匹配二月的一般日

在闰年的2月29日,我们还需要匹配所有其他日子的2月(1 - 28)在所有年

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

匹配日期:2018-02-012019-02-132020-02-25

非匹配日期:2000-02-30.2400-02-622018/02/28

3.5。匹配31天的月份

1月、3月、5月、7月、8月、10月和12月应该匹配1到31天:

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

匹配日期:2018-01-312021-07-312022-08-31.

非匹配日期:2018-01-322019-03-642018/01/31

3.6。匹配30天的月份

4月,6月,9月和11月的月份应在1到30天之间匹配:

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

匹配日期:2018-04-302019-06-302020-09-30

非匹配日期:2018-04-312019-06-312018/04/30

3.7。格雷戈里亚日期匹配者

现在我们可以将上述所有模式与单个匹配相结合,以进行完整gregoriandatematcher满足所有约束条件:

类GregorianDateMatcher实现DateMatcher{私有静态模式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][0 - 9] | | 1 2(主/ ]))$" + "|^((( 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();}}

我们已经使用过交替字符" | "至少匹配一个四个分支中的一个。因此,2月的有效日期要么与闰年2月29日的第一个分支相匹配,要么与闰年之后的任何一天的第二个分支相匹配128.。其余月份的日期与第三和第四分支相匹配。

由于我们没有优化这种模式,并有利于更好的可读性,因此可以随意尝试一段时间。

此时我们已经满足了所有的限制,我们在开始时介绍。

3.8。关于性能的说明

解析复杂的正则表达式可能会显著影响执行流的性能。本文的主要目的不是学习一种有效的方法来测试字符串在所有可能日期集合中的成员关系。

考虑使用LocalDate.parse ()如果需要验证日期的可靠和快速方法,则由Java8提供。

4.结论

在本文中,我们已经学会了如何通过提供格式规则,范围和月度的规则来使用定期表达式来匹配Gregorian日历的严格格式化日期。

本文中提供的所有代码都可用在Github。这是一个基于maven的项目,因此它应该很容易导入和运行。

Java底部

使用Spring 5和Spring Boot 2开始,通过学习的春天课程:

>>查看课程
1评论
最老的
最新
内联反馈
查看所有评论
评论在本文上关闭!