使用正則表達式匹配所有日期,並區別閏年、平年

    一、用正則表達式表示年份-月-日,我們以公元元年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,所有的日期都用正則表達式表示出來,並且區分了閏年和平年。從解題的過程我們可以看到,面對一個複雜問題無從下手時,我們不要慌,仔細進行分析,儘量把問題模塊化,分解後若干個小問題逐個解決,然後再把答案進行組合,這是較爲常用的方法。這與編寫程序時講求代碼儘量模塊化,降低代碼耦合度,以便於編寫和維護是同樣的道理。

    網上有關的文章已經不少了,自己之所以再寫一遍,一是幫助自己進一步捋清思路,提高技能;二是幫助記憶,便於日後查閱,俗話說:“好記性不如爛筆頭”。希望看到的朋友覺得有哪裏不對或有更好的解決方案,敬請指正!

 

 

 

 

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