正则表达式匹配日期中的有效日期
我需要帮助想出一个正则表达式来确保用户输入有效的日期
该字符串的格式为 mm/dd/yyyy
这是我到目前为止所想到的。
/\[1-9]|0[1-9]|1[0-2]\/\d{1,2}\/19|20\d\d/
我已经验证了正则表达式,其中用户不能输入大于 12 的日期,并且年份必须以“19”或“20”开头。我遇到的麻烦是找出一些验证这一天的逻辑。这一天不应超过31。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
0-31 的正则表达式:
或者如果您不想要前面带有零的日期(例如 05):
Regex for 0-31:
Or if you don't want days with a preceding zero (e.g. 05):
01-31
,那么只要有一些后端逻辑将日期验证为整个,如果需要的话。我看到当前的预期答案对于 10、20 来说失败了。
gawk 'BEGIN{ for(i=0;i<=32;i++){ if (i ~ /^([0-2]?[1-9]|3[01]) $/){print i " yes"}else {print i " no"} } }
^([0-2]?[1-9]|3[01]|10|20)$
请考虑以下解决方案...
1.确定需要匹配的集合:
{01,...,09},{10,...,31}
{10,...,31}
可以拆分为=> {10,...,29},{30,31}
{1,...,31} => {1,...,9},{10,...,31}
2.每个子集对应的正则表达式:
现在我们可以将
([0][1-9])
和([1-9])
分组在一起如([0]?[1-9])
。其中?
表示模式/符号出现 0 次或 1 次。 [更新] - 谢谢 @MattFrear 指出。所以生成的正则表达式是:
^(([0]? [1-9])|([1-2][0-9])|(3[01]))$
此处测试:http://regexr.com/?383k1 [更新]
01-31
then RegEx is fine so long as there is some backend logic that validates the date as a whole, if so desired.I see the expected answer currently fails for 10, 20.
gawk 'BEGIN{ for(i=0;i<=32;i++){ if (i ~ /^([0-2]?[1-9]|3[01])$/){print i " yes"}else {print i " no"} } }
^([0-2]?[1-9]|3[01]|10|20)$
So kindly consider the following solution...
1. Identify the sets that need to be matched:
{01,...,09},{10,...,31}
{10,...,31}
can be split into=> {10,...,29},{30,31}
{1,...,31} => {1,...,9},{10,...,31}
2. Corresponding regular expressions for each sub-set:
Now we can group
([0][1-9])
and([1-9])
together as([0]?[1-9])
. Where?
signifies 0 or 1 occurrences of the pattern/symbol. [UPDATE] - Thank you @MattFrear for pointing it out.So the resulting RegEx is:
^(([0]?[1-9])|([1-2][0-9])|(3[01]))$
Tested here: http://regexr.com/?383k1 [UPDATE]
其他解决方案很好,可能有效,等等。通常,您最终会想要多做一点,然后再多做一点,最终您会得到一些疯狂的代码和闰年,为什么您还要自己再做一次呢?
DateTime 及其格式化程序 是您的解决方案。使用它们!有时它们有点矫枉过正,但通常这对你来说是有效的。
$foo
现在是一个 DateTime 对象。享受。如果您的日期字符串格式不正确,
$foo
将是"undef"
并且$dayFormat->errstr
会告诉您原因。Other solutions are fine, probably work, etc. Usually, you end up wanting to do a bit more, and then a bit more, and eventually you have some crazy code, and leap years, and why are you doing it yourself again?
DateTime and its formatters are your solution. Use them! Sometimes they are a bit overkill, but often that works out for you down the road.
$foo
is now a DateTime object. Enjoy.If your date string wasn't properly formatted,
$foo
will be"undef"
and$dayFormat->errstr
will tell you why.来自 类别中的表达式:日期和时间
验证正确的天数一个月,看起来它甚至可以处理闰年。
您当然可以将
[\.\-/]
更改为/
以仅允许斜杠。From Expressions in category: Dates and Times
Validates the correct number of days in a month, looks like it even handles leap years.
You can of course change
[\.\-/]
with/
to only allow slashes.这并不那么困难......
This isn't all that hard...
如果您想检查有效日期,您要做的不仅仅是检查数字和范围。幸运的是,Perl 已经具备了您所需的一切。 Time::Piece 模块随 Perl 一起提供,可以解析日期。它知道如何解析日期并进行第一轮检查:
输出很有趣,这里没有其他解决方案可以接近处理这个问题。为什么 10/6/1582 是无效日期?它在公历中不存在,但这里有一个更简单的原因。
strptime
不处理 1900 年之前的日期。但还要注意
2/29/1900
会变成3/1/1900
。这很奇怪,我们应该解决这个问题,但能被 100 整除的年份中没有闰年。好吧,除非它们能被 400 整除,这就是2/29/2000
有效的原因。但让我们解决闰年问题。
tm
结构正在进行愚蠢的转换。如果无论月份如何,各个数字都在合理的范围内(天数为 0 到 31),则它将这些天数转换为秒并将其添加到偏移量中。这就是为什么 2/29/1900 会晚一天结束:29 给出的秒数与 3/1/1900 相同。如果日期有效,则应该返回相同的日期。由于我要往返这一点,所以在对它进行任何操作之前我会修复前导零的日期:现在输出是:
这有点长,但这就是我们有子例程的原因:
仍然需要正则表达式?好的,让我们使用
(??{...})
构造来决定模式是否应该失败。匹配一串数字并将其捕获到$1
中。现在,使用(??{...})
来制作模式的下一部分,使用您喜欢的任何 Perl 代码。如果接受捕获,则返回空模式。如果拒绝,则返回模式(*FAIL)
,这会立即导致整个匹配失败。不再需要棘手的交替。这个使用了 v5 中新的 链式比较。 32(虽然我对此仍然心存疑虑):If you want to check for valid dates, you have to do much more than check numbers and ranges. Fortunately, Perl already has everything you need for this. The Time::Piece module comes with Perl and can parse a date. It knows how to parse dates and do the first round of checks:
The output is interesting and no other solution here is close to handling this. Why is 10/6/1582 an invalid date? It doesn't exist in the Gregorian calendar, but there's a simpler reason here.
strptime
doesn't handle dates before 1900.But also notice that
2/29/1900
gets turned into3/1/1900
. That's weird and we should fix that, but there's no leap years in years divisible by 100. Well, unless they are divisible by 400, which is why2/29/2000
works.But let's fix that leap year issue. The
tm
struct is going a dumb conversion. If the individual numbers are within a reasonable range (0 to 31 for days) regardless of the month, then it converts those days to seconds and adds them to the offset. That's why 2/29/1900 ends up a day later: that 29 gives the same number of seconds as 3/1/1900. If the date is valid, it should come back the same. And since I'm going to roundtrip this, I fix up the date for leading zeros before I do anything with it:Now the output is:
That's all a bit long, but that's why we have subroutines:
Still want a regex? Okay, lets use the
(??{...})
construct to decide if a pattern should fail. Match a bunch of digits and capture that into$1
. Now, use(??{...})
to make the next part of the pattern, using any Perl code you like. If you accept the capture, return a null pattern. If you reject it, return the pattern(*FAIL)
, which immediately causes the whole match to fail. No more tricky alternations. And this one uses the new chained comparison in v5.32 (although I still have misgivings about it):尝试一下:
<代码>/(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/((19|20 )\d\d)/
Try it:
/(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/((19|20)\d\d)/
正则表达式是必须的吗?如果没有,您最好使用不同的方法,例如
DateTime::Format::DateManip
Is regular expression a must? If not, you better off using a different approach, such as
DateTime::Format::DateManip
0-31 天的正则表达式:
0[1-9]|[12]\d|3[01]) 无前缀 0 - 当“1”、“23”...
([1-9]|[12] \d|3[01]) 带前缀 0 - 当“01”、“04”时
(0?[1-9]|[12]\d|3[01]) - 带或不带“0” - 当“ ”
Regex for 0-31 day:
0[1-9]|[12]\d|3[01]) without prefix 0 - when "1", "23"...
([1-9]|[12]\d|3[01]) with prefix 0 - when "01", "04"
(0?[1-9]|[12]\d|3[01]) - with or without "0" - when ""
更简单的正则表达式:
考虑接受的答案和这个表达式:
This matches 01 but not 1
接受的答案中的另一个表达式:
This matches 1 but not 01
不可能添加 OR 子句来让它们都工作。
我建议的那个与两者都匹配。希望这有帮助。
Simpler regex:
Consider the accepted answer and this expression:
This matches 01 but not 1
The other expression in the accepted answer:
This matches 1 but not 01
It is not possible to add an OR clause to get them both working.
The one I suggested matches both. Hope this helps.
我已经处理这个问题有一段时间了,我想出的最好的正则表达式如下:
它将匹配以下数字:它
与以下数字不匹配:
I have been working with this some time and the best regex I've came up with is the following:
It will match the following numbers:
It does not match the following: