使用正则表达式匹配所有日期,并区别闰年、平年

    一、用正则表达式表示年份-月-日,我们以公元元年0001-01-01开始一直到9999-12-31结束。用字母YYYY表示年,用MM表示月,用DD表示日,格式为:YYYY-MM-DD。

    二、区分闰年和平年,首先来了解一下闰年的概念:关于公历闰年是这样规定的:地球绕太阳公转一周叫做一回归年,一回归年长365日5时48分 46秒。因此,公历规定有平年和闰年,平年一年有365日,比回归年短0.2422日,四年共短0.9688日,故每四年增加一日,这一年有366日,就是闰年。但四年增加一日比四个回归年又多0.0312日,400年后将多3.12日,故在400年中少设3个闰年,也就是在400年中只设97个闰年,这样公历年的平均长度与回归年就相近似了。由此规定:年份是整百数的必须是400的倍数才是闰年,例如1900年、2100年就不是闰年。

由以上概念可知闰年必须满足的条件:能被4整除但不能被100整除的年份或者能被400整除的年份都是闰年。

    三、根据以上概念,我们将现来看年份:

(一)、年份(YYYY)0001-01-01到9999-12-31的正则表达式很容易得出是:

  String years = “[0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}”

    难点在于如何区分闰年,根据闰年的概念:能被4整除但不能被100整除的年份或者能被400整除的年份都是闰年。我们分两步分讲解:

1、能被4整除但不能被100整除

    不能被100整除,也就是十位和个位不是均为0即可。难点在于能被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。然后我们再看三位、四位…数的倍数,我们发现无论是倍数是几位数,前两位数都是上面这些数。因此只要得出它们的正则表达式即可。认真观察发现:当十位数是0是,个位数有4,8;当十位数是1,3,5,7,9时个位数只能是2,6;当十位数是2,4,6,8时个位数只能是0,4,8。因此,能被4整除但不能被100整除的数用正则表达式表示为:0[48]|[2468][048]|[13579][26]。那么能被4整除但不能被100整除的四位数即为:

String leapYears1 = “([0-9]{2})(0[48]|[2468][048]|[13579][26])”

    2、能被400整除的数

    能被400整除就是既能被4整除又可以被100整除的数,其实就是能被4整除并且十位和个位均为0的数,因此很容易得出正则表达式为:

    String leapYears2 = “(0[48]|[2468][048]|[13579][26])00”

    结合上述两种情况我们得出闰年的正则表达式:

    String leapYears = “leapYears1|leapYears2”  

    即为:([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[13579][26])00)

    (二) 最难的部分解决了,月份和日相对就简单了:

     月份(MM)我们知道1,3,5,7,8,10,12月是31天,4,6,9,11月是30天,2月平年为28天,闰年为29天。因此不难得出月份及其对应天数的正则表达式如下:

  •      大月表示为:String  bigMonth = “(0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])”
  •     小月表示为:String littleMonth = “(0[469]|11)-(0[1-9]|[12][0-9]|30)”
  •     平年的2月表示为:String february = “02-(0[1-9]|1[0-9]|2[0-8])”

    四、有了上面的结论为基础,现在我们再按完整的年-月-日(YYYY-MM-DD)的格式,把上面的字符串表达式进行如下组合:

    String ragularExpression = “((years)-((bigMonth)|(littleMonth)|(February)))|((leapYears)-02-29)”

    注意:因为ragularExpression的前半部分“((years)-((bigMonth)|(littleMonth)|(February)))”表示的日期不包含闰年的YYYY-02-29,也就是除每个闰年的2月29日那天之外所有的日期都有,所以我们只需要在后面补上每个闰年的2月29日那天,即“(leapYears)-02-29”。

    将ragularExpression变成正则表达式就是:

(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|1[0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[13579][26])00))-02-29)

    至此,我们就把从0001-01-01至9999-12-31,所有的日期都用正则表达式表示出来,并且区分了闰年和平年。从解题的过程我们可以看到,面对一个复杂问题无从下手时,我们不要慌,仔细进行分析,尽量把问题模块化,分解后若干个小问题逐个解决,然后再把答案进行组合,这是较为常用的方法。这与编写程序时讲求代码尽量模块化,降低代码耦合度,以便于编写和维护是同样的道理。

    网上有关的文章已经不少了,自己之所以再写一遍,一是帮助自己进一步捋清思路,提高技能;二是帮助记忆,便于日后查阅,俗话说:“好记性不如烂笔头”。希望看到的朋友觉得有哪里不对或有更好的解决方案,敬请指正!

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章