这个正则是从网上抄了以后修改的,具体网址记不清了,修改内容如下:
- 它原来简写\d用[0-9]代替,建议大家写正则如非必要不要用简写.
- 修改年月日部份分组(用括号分组)为以下格式以方便程序解析.
“年月日完整格式”+“完整年份” + “年前二位” + “年后二位” + “月” + "天"共6个字段,如下:
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2010-3-23','(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2010-11-23','(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2010-2-28','(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2012-2-29','(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2020-2-29','(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2004-2-29','(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('3600-2-29','((([13579]6)(00))-(0?2)-(29))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('2000-2-29','((([2468][048])(00))-(0?2)-(29))') as f
union all
select f[1],f[2],f[3],f[4],f[5],f[6]
from regexp_matches('3200-2-29','((([3579]2)(00))-(0?2)-(29))') as f
完整正则表达式
^(((((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|((([13579]6)(00))-(0?2)-(29))|((([2468][048])(00))-(0?2)-(29))|((([3579]2)(00))-(0?2)-(29)))T((([0-1][0-9])|([2][0-4])):(([0-5])([0-9])):(([0-5])([0-9]))))$
虽然看起来很复杂,但是我们可以分解开来看问题就简单了.这里建议用Notepad++以方便查看括号对,Notepad一组括号可以标红.
分解正则表达式
^(
(
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|
(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|
(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|
(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|
((([13579]6)(00))-(0?2)-(29))|
((([2468][048])(00))-(0?2)-(29))|
((([3579]2)(00))-(0?2)-(29))
)
T(
(([0-1][0-9])|([2][0-4]))
:(([0-5])([0-9]))
:(([0-5])([0-9]))
)
)$
select f from regexp_matches('2019-12-31T12:19:24','^(((((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|((([13579]6)(00))-(0?2)-(29))|((([2468][048])(00))-(0?2)-(29))|((([3579]2)(00))-(0?2)-(29)))T((([0-1][0-9])|([2][0-4])):(([0-5])([0-9])):(([0-5])([0-9]))))$') as f
年部份
((1[6-9]|[2-9][0-9])([0-9]{2}))
(1[6-9]|[2-9][0-9]) #表示日期开头必须为16-19或者20-99
([0-9]{2}) #表示范围为00-99
#组合起来日期范围就是1600-9999年
月部份
(0?[13578]|1[02]) #表示只允许为01/03/05/07/08(其中0可填或不填)或10/12
(0?[469]|11) #表示只允许为04/06/09(其中0可填或不填)或11
(0?2) #表示只允许为02(其中0可填或不填)
月天部分
#0?[1-9]表示01/02/03/04/05/06/07/08/09.[12][0-9]同理范围为11-19或21-29
(0?[1-9]|[12][0-9]|3[01]) #表示1-31天
(0?[1-9]|[12][0-9]|30) #表示1-30天
(0?[1-9]|1[0-9]|2[0-8]) #表示1-28天
小结
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01])) #表示年范围为1600-9999,月范围为01/03/05/07/0810/12,月天范围为1-31天
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30)) #表示年范围为1600-9999,月范围为04/06/09/11,月天范围为1-30天
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8])) #表示年范围为1600-9999,月范围为2,月天范围为1-28天.这里只判断了平年2月份的天数
判断具有29天的闰年
判断闰年还是平年,闰年一年有366天,平年一年有365天
遵循的规律为: 四年一闰,百年不闰,四百年再闰.
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
根据以上知识得知2月份比较特殊,平年有28天,闰年有29天,因此需要专门判断
(1[6-9]|[2-9][0-9]) #这部份知识前面已经计划过,因此这里用年份开头二位数用xx代替
(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-29) #表示xx12/xx16/xx32/xx36/xx52/xx56/xx72/xx76/xx92/xx96年的二月是闰年有29天(四年一闰).
(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-29) #表示xx20/xx24/xx28/xx40/xx44/xx48/xx60/xx64/xx68/xx80/xx84/xx88年的二月是闰年有29天(四年一闰).
(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-29) #表示xx04/xx08年的二月是闰年有29天(四年一闰).
((([13579]6)00)-(0?2)-29) #表示1600/3600/5600/7600/9600年的二月是闰年有29天(百年不闰,四百年再闰).
((([2468][048])00)-(0?2)-29) #表示2000/2400/2800/4000/4400/4800/6000/6400/6800/8000/8400/8800年的二月是闰年有29天(百年不闰,四百年再闰).
((([3579]2)00)-(0?2)-29) #表示3200/5200/7200/9200年的二月是闰年有29天(百年不闰,四百年再闰).
判断年月日完整正则
^((((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|((([13579]6)(00))-(0?2)-(29))|((([2468][048])(00))-(0?2)-(29))|((([3579]2)(00))-(0?2)-(29)))$
分解正则表达式
^(
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|
(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|
(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|
(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|
(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|
((([13579]6)(00))-(0?2)-(29))|
((([2468][048])(00))-(0?2)-(29))|
((([3579]2)(00))-(0?2)-(29))
)$
select f from regexp_matches('3200-2-29','^((((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[13578]|1[02])-(0?[1-9]|[12][0-9]|3[01]))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?[469]|11)-(0?[1-9]|[12][0-9]|30))|(((1[6-9]|[2-9][0-9])([0-9]{2}))-(0?2)-(0?[1-9]|1[0-9]|2[0-8]))|(((1[6-9]|[2-9][0-9])([13579][26]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])([2468][048]))-(0?2)-(29))|(((1[6-9]|[2-9][0-9])(0[48]))-(0?2)-(29))|((([13579]6)(00))-(0?2)-(29))|((([2468][048])(00))-(0?2)-(29))|((([3579]2)(00))-(0?2)-(29)))$') as f
时间部分
时间部分就比较简单了,其中小时范围为1-24,分钟和秒范围0-59)
^T((([0-1][0-9])|([2][0-4])):(([0-5])([0-9])):(([0-5])([0-9])))$
分解正则表达式
T(
(([0-1][0-9])|([2][0-4]))
:(([0-5])([0-9]))
:(([0-5])([0-9]))
)
select f from regexp_matches('T12:19:24','^(T((([0-1][0-9])|([2][0-4])):(([0-5])([0-9])):(([0-5])([0-9]))))$') as f