Answer
Brief
所以我决定制作一个非常好的正则表达式,它实际上可以在闰年正常工作!然后我添加了您所需的其余逻辑,瞧,真是太美了!
Code
请参阅此处使用的正则表达式 https://regex101.com/r/bnUaF8/2
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b
或者在一行...
请参阅此处使用的正则表达式 https://regex101.com/r/ZDifJ1/1
\b(?:(?:0[1-9]|1\d|2[0-8])\/(?:02)\/(?:\d+)|(?:0[1-9]|1\d|2\d)\/(?:02)\/(?:(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))|(?:0[1-9]|1\d|2\d|30)\/(?:0[469]|11)\/(?:\d+)|(?:0[1-9]|1\d|2\d|3[01])\/(?:0[13578]|1[02])\/(?:\d+))\ (?:(?:0\d|1[01]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?\ ?(?:(?i)[ap]m|[ap]\.m\.(?-i))|(?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?)\b
解释
我将解释第一个版本,因为第二个版本只是它的精简版本。请注意,可以轻松更改正则表达式以适应更多格式(仅接受一种稍有变化的格式,但这是一个非常可定制的正则表达式)。
-
d_days28:匹配任意数字
01
to 28
-
d_days29:匹配任意数字
01
to 29
-
d_days30:匹配任意数字
01
to 30
-
d_days31:匹配任意数字
01
to 31
-
d_month28:匹配可能只有的月份28天(二月 - 因此
02
)
-
d_month29:匹配可能只有的月份29天(二月 - 因此
02
)
-
d_month30:匹配仅具有的月份30天(四月、六月、九月、十一月 - 因此
04, 06, 09, 11
)
-
d_month31:匹配仅具有的月份31天(一月、三月、五月、七月、八月、十月、十二月 - 因此
01, 03, 05, 07, 08, 10, 12
)
-
d_year:匹配任何年份(必须至少有一位数字
\d
)
-
d_yearLeap: I'll break this into multiple segments for better clarity
-
\d*?
- Match one of the following
-
(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))
- 匹配以下一项
-
(?:(?!00)[02468][048]|[13579][26])
- Match one of the following
- One of
02468
,后跟其中之一048
, 但不是00
- One of
13579
,后跟其中之一26
-
(?:(?:[02468][048]|[13579][26])00)
- Match one of the following, followed by 00
- One of
02468
,后跟其中之一048
- One of
13579
,后跟其中之一26
-
[48]00
- 匹配400
or 800
-
[48]
- 匹配4
or 8
-
(?=\D|\b)
- 确保后面的内容是非数字字符\D
或单词边界字符\b
-
d_format:这指向之前的组,以确保月份格式正确并符合日/月和日/年(闰年)要求,以便我们可以确保正确的日期验证
-
t_period: This was added in case others needed this for validation purposes
- 确保期间是
am, pm, a.m, p.m
或它们各自的大写版本(包括诸如a.M
当使用多种情况时)
-
t_hours12:匹配从
00
to 11
-
t_hours24:匹配从
00
to 23
-
t_分钟:匹配任意分钟
00
to 59
-
t_秒:匹配任意秒
00
to 59
-
t_毫秒:匹配任意3位数字(
000
to 999
)
-
t_format:这指向之前的组,以确保时间格式正确。我添加了一个额外的时间设置(以及包括毫秒和时间段的附加内容供其他人使用)
-
dt_格式:要检查的日期时间格式(在您的情况下是
date time
- 以空格分隔
特点)
- 定义块之后是
\b(?&dt_format)\b
,它简单地匹配dt_format
如上所述,确保它之前和取代的内容是单词边界字符(或没有字符)\b
闰年
为了进一步了解正则表达式的闰年部分......
我假设如下:
- All years are NOT leap years, unless, the following is true
- ((年模
4
is 0
) AND(年模100
is not 0
)) OR(年模400
is 0
)
- Source: 闰年计算 https://stackoverflow.com/a/725111/3600709
- 闰年一直存在(至少从第一年开始)——因为我不想开始假设并做更多的研究。
正则表达式的工作原理是确保:
- 所有以以下日期结束的闰年
0, 4, 8
are preceded by a 0, 2, 4, 6, 8
(所有这些都会导致0
模数之后 -> 即24 % 4 = 0
)
- 所有以以下日期结束的闰年
2, 6
are preceded by a 1, 3, 5, 7, 9
(所有这些都会导致0
模数之后 -> 即32 % 4 = 0
)
- 所有以以下日期结束的闰年
00
, 对于 1. 和 2.,被否定((?!00)
做这个)
- 所有以以下日期结束的闰年
00
are preceded by 1. 和 2.(完全一样,因为4 * 100 = 400
- 除了最后两位数字之外,不需要更改任何内容)
- 添加年份
400, 800, 4, 8
因为他们不满足上述任何条件
Edits
2017 年 10 月 25 日
谢谢@sln https://stackoverflow.com/users/557597/sln用于输入闰年功能。由于以下中提供的更改,下面的正则表达式执行速度稍快sln对此答案的评论 https://stackoverflow.com/a/46940144/3600709(关于一个单独的问题)。改变了(?:(?!00)[02468][048]|[13579][26])
to (?:0[48]|[13579][26]|[2468][048])
在闰年部分。
请参阅此处使用的正则表达式 https://regex101.com/r/bnUaF8/3
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:0[48]|[13579][26]|[2468][048])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D|\b))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b