范例 |
正则表达式范例 |
数字范围 |
浮点数 |
电子邮件地址 |
IP 地址 |
有效日期 |
数字日期转换为文本 |
信用卡号码 |
符合完整行 |
删除重复行 |
编程 |
两个相近的字词 |
陷阱 |
灾难性的回溯 |
过多重复 |
阻断服务 |
让所有内容都是选项 |
重复捕获组 |
混合 Unicode 和 8 比特 |
更多内容 |
简介 |
正则表达式快速入门 |
正则表达式教程 |
替换字符串教程 |
应用程序和语言 |
正则表达式范例 |
正则表达式参考 |
替换字符串参考 |
符合有效日期的正则表达式
^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$
符合从 1900-01-01 到 2099-12-31,且有四个分隔符号选择的 yyyy-mm-dd 格式日期。锚点可确保整个变量是一个日期,而不是包含日期的文本片段。年份由 (19|20)\d\d
符合。我使用 交替 来允许前两个数字为 19 或 20。括号是强制性的。如果我省略它们,正则表达式引擎会寻找 19 或正则表达式的其余部分,这会符合介于 2000-01-01 和 2099-12-31 之间的日期。括号是唯一能阻止垂直线将整个正则表达式分成两个选项的方法。
月份由 0[1-9]|1[012]
匹配,再次用括号包起来以保持两个选项在一起。通过使用 字符类别,第一个选项会匹配 01 到 09 之间的数字,而第二个选项会匹配 10、11 或 12。
正则表达式的最后一部分包含三个选项。第一个选项会匹配 01 到 09 之间的数字,第二个选项会匹配 10 到 29 之间的数字,而第三个选项会匹配 30 或 31。
巧妙地使用交替让我们可以排除无效的日期,例如 2000-00-00,而不用交替就无法排除。要做到真正完美,您必须将月份拆分成不同的选项,以考量月份的长度。上述正则表达式仍然会匹配 2003-02-31,而这并非有效的日期。让前导零为可选的可以是另一个增强功能。
如果您想要强制分隔符一致,可以使用 反向引用。 ^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$
会匹配 1999-01-01
,但不会匹配 1999/01-01
。
同样地,您要让正则表达式多么复杂取决于您使用它的数据,以及如果出现不想要的匹配,问题会有多严重。如果您在脚本中验证用户的日期输入,在正则表达式之外运行某些检查可能比较容易。例如,当年份不是闰年时排除 2 月 29 日,在脚本语言中运行会容易得多。使用简单的算术来检查年份是否可被 4 整除(且不可被 100 整除,除非可被 400 整除),会比使用正则表达式容易得多。
以下是如何在 Perl 中检查有效的日期。我也加入了括号,将年份截取到反向引用中。
sub isvaliddate {
my $input = shift;
if ($input =~ m!^((?:19|20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$!) {
# At this point, $1 holds the year, $2 the month and $3 the day of the date entered
if ($3 == 31 and ($2 == 4 or $2 == 6 or $2 == 9 or $2 == 11)) {
return 0; # 31st of a month with 30 days
} elsif ($3 >= 30 and $2 == 2) {
return 0; # February 30th or 31st
} elsif ($2 == 2 and $3 == 29 and not ($1 % 4 == 0 and ($1 % 100 != 0 or $1 % 400 == 0))) {
return 0; # February 29th outside a leap year
} else {
return 1; # Valid date
}
} else {
return 0; # Not a date
}
}
若要比对 mm/dd/yyyy 格式的日期,请将正则表达式重新排列为 ^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$
。对于 dd-mm-yyyy 格式,请使用 ^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$
。