我需要用正则表达式验证格式为dd/mm/yyyy的日期字符串。

这个正则表达式验证dd/mm/yyyy,但不验证像31/02/4500这样的无效日期:

^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$

什么是有效的正则表达式来验证支持闰年的dd/mm/yyyy格式?


当前回答

我正在使用一个只接受MM/DD/YYYY格式的API。我找不到任何一篇文章能像Ofir的回答一样解释闰年,所以我对它进行了调整,并在这里重新发布给任何可能需要它的人。

/^(?:(?:(?:0[13578]|1[02])(\/)31)\1|(?:(?:0[1,3-9]|1[0-2])(\/)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:02(\/)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/)(?:0[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/

其他回答

进一步扩展了@AlokChaudhary给出的正则表达式,以支持:

1. dd mmm YYYY(除了dd-mmm-YYYY, dd/mmm/YYYY, dd.mmm.YYYY)。

2. 所有大写字母格式的mmm(除了标题格式)

dd mmm YYYY,例如2026年4月30日或2028年12月24日是流行的。

扩展正则表达式:

(^(?:(?:(?:31(?:(?:([-.\/])(?:0?[13578]|1[02])\1)|(?:([-.\/ ])(?:Jan|JAN|Mar|MAR|May|MAY|Jul|JUL|Aug|AUG|Oct|OCT|Dec|DEC)\2)))|(?:(?:29|30)(?:(?:([-.\/])(?:0?[13-9]|1[0-2])\3)|(?:([-.\/ ])(?:Jan|JAN|Mar|MAR|Apr|APR|May|MAY|Jun|JUN|Jul|JUL|Aug|AUG|Sep|SEP|Oct|OCT|Nov|NOV|Dec|DEC)\4))))(?:(?:1[6-9]|[2-9]\d)?\d{2}))$|^(?:29(?:(?:([-.\/])(?:0?2)\5)|(?:([-.\/ ])(?:Feb|FEB)\6))(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))$|^(?:(?:0?[1-9]|1\d|2[0-8])(?:(?:([-.\/])(?:(?:0?[1-9]|(?:1[0-2])))\7)|(?:([-.\/ ])(?:Jan|JAN|Feb|FEB|Mar|MAR|May|MAY|Jul|JUL|Aug|AUG|Oct|OCT|Dec|DEC)\8))(?:(?:1[6-9]|[2-9]\d)?\d{2}))$)

Regex演示中包含的测试用例

特性(保留):

闰年检查(2月29日验证)包括以下逻辑:(能被4整除但不能被100整除)或(能被400整除) 支持1600 ~ 9999年 支持dd/mm/YYYY、dd-mm-YYYY、dd.mm.YYYY(不支持dd mm YYYY) 支持dd mmm YYYY、dd-mmm-YYYY、dd/mmm/YYYY、dd.mmm.YYYY(新增dd mmm YYYY)。mmm可以是大写的,如DEC或标题格式,如DEC)

一些额外的小润色如下:

Included the fix by Ofir Luzon on February 14th 2019 to remove a comma that was in the regex which allowed dates like 29-0,-11 [error replicated to Alok Chaudhary's regex] Replaced (\/|-|\.) by ([-.\/]) to minimize the use of backslash. \/ is still used in order to support some regex flavor e.g. PCRE(PHP) although some other regex flavor e.g. Python can simply use / inside the character class [ ] Added a pair of parenthesis () surrounding the whole regex to make it a capturing group for the whole matching string. This is useful for people using findAll type of functions to get a matching item list (e.g. re.findall in Python). This enable us to capture all the matching strings within a mult-line string with the following codes:

Re.findall示例代码:

match_list = re.findall(regex, source_string)
for item in match_list:
    print(item[0])

扩展正则表达式图像:

应该归功于Ofir Luzon和Alok Chaudhary,他们为我们所有人创造了如此优秀的正则表达式!

另一种答案,根据月(mm)和年(yyyy)验证日(dd)(即,在闰年也验证2月29日),并允许年范围从0001到9999(根据公历,0000是无效年)

^(?:(?:(?:0[1-9]|[12]\d|3[01])/(?:0[13578]|1[02])|(?:0[1-9]|[12]\d|30)/(?:0[469]|11)|(?:0[1-9]|1\d|2[0-8])/02)/(?!0000)\d{4}|(?:(?:0[1-9]|[12]\d)/02/(?:(?!0000)(?:[02468][048]|[13579][26])00|(?!..00)\d{2}(?:[02468][048]|[13579][26]))))$

这是一个正则表达式,用于匹配日期格式的字符串,YYYY-MM-DD,使用不同类型的分隔符。它甚至在句子中匹配字符串,并且日期以st, nd和其他结尾。

举个例子,它与下面句子中的日期相匹配:

"Her birthday is 2022 February 23rd; I will present here a gift."

"Her birthday is 2022 Feb 23rd; I will present here a gift."

"Her birthday is 2022 02 23; I will present here a gift."

这是日期正则表达式:

"\b
(?<YYYY>[0-9]{4})
(?<!0000)(?<sep>[ /.,-])
(?|
    (?:(?<MM>0[13578]|1[02]|Jan(?:uary)?|Mar(?:ch)?|May|Jul(?:y)?|Aug(?:ust)?|Oct(?:ober)?|Dec(?:ember)?)\g{sep}(?<DD>0[1-9]|[12][0-9]|3[01]))|
    (?:(?<MM>0[469]|11|Apr(?:il)?|Jun(?:e)?|Sep(?:tember)?|Nov(?:ember)?)\g{sep}(?<DD>0[1-9]|[12][0-9]|30))|
    (?:(?<MM>02|Feb(?:ruary)?)\g{sep}(?<DD>0[1-9]|[12][0-9]))
)
(?:
    (?<=[023][1])st|
    (?<=[02][2])nd|
    (?<=[02][3])rd|
    (?<=(?:0[4-9])|(?:1[0-9])|20|(?:2[4-9])|30)th
)?
[,;.]?
\b"x

以我之见,对于正则表达式来说,检查闰年是没有意义的,因为可以为它编写简单、清晰和可理解的一行代码:

is_leap_year(y) = ((y%4 == 0) && (y%100 != 0)) || (y%400 == 0)

正则表达式是用来匹配字符串的,而不是用来进行计算的。最好的方法是匹配字符串,然后将捕获的MM组传递给is_leap_year函数(如果是02、Feb或February),以验证字符串。

year  = ((20[012]\d|19\d\d)|(1\d|2[0123])) 
month = ((0[0-9])|(1[012]))
day   = ((0[1-9])|([12][0-9])|(3[01]))

year-month-day = (((20[012]\d|19\d\d)|(1\d|2[0123]))-((0[0-9])|(1[012]))-((0[1-9])|([12][0-9])|(3[01])))
day-month-year = (((0[1-9])|([12][0-9])|(3[01]))-((0[0-9])|(1[012]))-((20[012]\d|19\d\d)|(1\d|2[0123])))
year/month/day = (((20[012]\d|19\d\d)|(1\d|2[0123]))\/((0[0-9])|(1[012]))\/((0[1-9])|([12][0-9])|(3[01])))
month/day/year = (((0[0-9])|(1[012]))\/((0[1-9])|([12][0-9])|(3[01]))\/((20[012]\d|19\d\d)|(1\d|2[0123])))
day/month/year = (((0[1-9])|([12][0-9])|(3[01]))\/((0[0-9])|(1[012]))\/((20[012]\d|19\d\d)|(1\d|2[0123])))
day.month.year = (((0[1-9])|([12][0-9])|(3[01]))\.((0[0-9])|(1[012]))\.((20[012]\d|19\d\d)|(1\d|2[0123])))
year.month.day = (((20[012]\d|19\d\d)|(1\d|2[0123]))\.((0[0-9])|(1[012]))\.((0[1-9])|([12][0-9])|(3[01])))


all = (((20[012]\d|19\d\d)|(1\d|2[0123]))-((0[0-9])|(1[012]))-((0[1-9])|([12][0-9])|(3[01])))|(((0[1-9])|([12][0-9])|(3[01]))-((0[0-9])|(1[012]))-((20[012]\d|19\d\d)|(1\d|2[0123])))|(((20[012]\d|19\d\d)|(1\d|2[0123]))\/((0[0-9])|(1[012]))\/((0[1-9])|([12][0-9])|(3[01])))|(((0[0-9])|(1[012]))\/((0[1-9])|([12][0-9])|(3[01]))\/((20[012]\d|19\d\d)|(1\d|2[0123])))|(((0[1-9])|([12][0-9])|(3[01]))\/((0[0-9])|(1[012]))\/((20[012]\d|19\d\d)|(1\d|2[0123])))|(((0[1-9])|([12][0-9])|(3[01]))\.((0[0-9])|(1[012]))\.((20[012]\d|19\d\d)|(1\d|2[0123])))|(((20[012]\d|19\d\d)|(1\d|2[0123]))\.((0[0-9])|(1[012]))\.((0[1-9])|([12][0-9])|(3[01])))

它的工作是

yyyy-mm-dd
dd-mm-yyyy
yyyy/mm/dd
mm/dd/yyyy
dd/mm/yyyy
dd.mm.yyyy
yyyy.mm.dd

yy-mm-dd
dd-mm-yy
yyyy/mm/dd
mm/dd/yy
dd/mm/yy
dd.mm.yy
yy.mm.dd

但不适用于日= d或月= m,例如d.m.y yyyy

所有示例-此处输入链接描述

在这里找到这个reg ex

^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$

这将正确地验证mm/dd/yyyy格式和有效日期(但不是m/d/yyyy)。

一些测试