我正在尝试编写一个验证日期的正则表达式.正则表达式需要匹配以下内容
M/d/YYYY
MM/DD/YYYY
单个数字月份可以从前导零开始(例如:03/12/2008)
单位数天可以从前导零开始(例如:2008年3月2日)
不能包括2月30日或2月31日(例如:2008年2月31日)
到目前为止我有
^(([1-9]|1[012])[-/.]([1-9]|[12][0-9]|3[01])[-/.](19|20)\d\d)|((1[012]|0[1-9])(3[01]|2\d|1\d|0[1-9])(19|20)\d\d)|((1[012]|0[1-9])[-/.](3[01]|2\d|1\d|0[1-9])[-/.](19|20)\d\d)$
这恰当匹配除了它还包括2/30/2008和2/31/2008.
有人有更好的建议吗?
编辑:我在RegExLib上找到了答案
^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$
它匹配遵循MM/DD/YYYY格式的所有有效月份.
谢谢大家的帮助.
这不适合使用正则表达式.你最好还是用
[0-9]{2}/[0-9]{2}/[0-9]{4}
然后用更高级别的语言检查范围.
这是Reg ex,它匹配所有有效日期,包括闰年.格式接受mm/dd/yyyy或mm-dd-yyyy或mm.dd.yyyy格式
^(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/|-|\.)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})$
礼貌Asiq Ahamed
我登陆这里因为这个问题的标题很广泛,我正在寻找一个可以用来匹配特定日期格式(如OP)的正则表达式.但后来我发现,由于许多答案和评论都得到了全面的强调,因此在提取与质量差或非结构化源数据混合的日期时,有许多陷阱会使构建有效模式变得非常棘手.
在我对这些问题的探索中,我提出了一个系统,通过将四个更简单的子表达式排列在分隔符上,以及命令中年,月,日字段的有效范围,可以构建正则表达式.你需要.
这些是 :-
定界符
[^\w\d\r\n:]
这将匹配任何不是单词字符,数字字符,回车符,换行符或冒号的内容.冒号必须在那里以防止在看起来像日期的时间匹配(参见我的测试数据)
您可以优化模式的这一部分以加速匹配,但这是检测大多数有效分隔符的良好基础.
但请注意; 它将匹配一个字符串与混合分隔符,如2/12-73,可能实际上不是一个有效的日期.
年份值
(\d{4}|\d{2})
这匹配一组两位或四位数,在大多数情况下这是可以接受的,但是如果你处理的是0-999年或9999年以上的数据,你需要决定如何处理这个数据,因为在大多数情况下是1,3或> 4位数年份是垃圾.
月值
(0?[1-9]|1[0-2])
匹配1到12之间的任何数字,有或没有前导零 - 注意:0和00不匹配.
日期值
(0?[1-9]|[12]\d|30|31)
匹配1到31之间的任何数字,有或没有前导零 - 注意:0和00不匹配.
此表达式匹配日期,月份,年份格式的日期
(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})
但它也会匹配部分年份,月份日期.它也应该与边界运算符一起预订,以确保选择整个日期字符串,并防止从格式不正确的数据中提取有效的子日期,即没有边界标记20/12/194匹配为20/12/19和101/12/1974比赛为01/12/1974
将下一个表达式的结果与上面的表达式的结果与废话部分(下面)中的测试数据进行比较
\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b
这个正则表达式没有验证,所以一个格式良好但无效的日期,如31/02/2001将匹配.这是一个数据质量问题,正如其他人所说,你的正则表达式不需要验证数据.
因为您(作为开发人员)无法保证源数据的质量,您需要在代码中执行和处理其他验证,如果您尝试匹配并验证RegEx中的数据,它会变得非常混乱并且变得很难支持没有非常简洁的文档.
垃圾进垃圾出.
话虽如此,如果你确实有混合格式的日期值变化,你必须提取尽可能多的; 你可以将几个表达式组合在一起;
这个(灾难性的)表达式与DMY和YMD日期相匹配
(\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b)|(\b(0?[1-9]|1[0-2])[^\w\d\r\n:](0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](\d{4}|\d{2})\b)
但是你无法判断像1969年6月9日这样的日期是9月6日还是6月9日.我正在努力想到一个不会在某个地方出现问题的情况,这是不好的做法,你不应该像那样处理它 - 找到数据所有者并用治理锤击中它们.
最后,如果你想匹配一个没有分隔符的YYYYMMDD字符串,你可以把一些不确定性排除在外,表达式看起来像这样
\b(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12]\d|30|31)\b
但请再次注意,它将匹配格式良好但无效的值,如20010231(2月31日!):)
测试数据
在试验这个线程中的解决方案时,我最终得到了一个测试数据集,其中包括各种有效和无效的日期以及一些您可能想要或可能不想匹配的棘手情况,即可能与日期和日期匹配的时间.多行.
我希望这对某人有用.
Valid Dates in various formats Day, month, year 2/11/73 02/11/1973 2/1/73 02/01/73 31/1/1973 02/1/1973 31.1.2011 31-1-2001 29/2/1973 29/02/1976 03/06/2010 12/6/90 month, day, year 02/24/1975 06/19/66 03.31.1991 2.29.2003 02-29-55 03-13-55 03-13-1955 12\24\1974 12\30\1974 1\31\1974 03/31/2001 01/21/2001 12/13/2001 Match both DMY and MDY 12/12/1978 6/6/78 06/6/1978 6/06/1978 using whitespace as a delimiter 13 11 2001 11 13 2001 11 13 01 13 11 01 1 1 01 1 1 2001 Year Month Day order 76/02/02 1976/02/29 1976/2/13 76/09/31 YYYYMMDD sortable format 19741213 19750101 Valid dates before Epoch 12/1/10 12/01/660 12/01/00 12/01/0000 Valid date after 2038 01/01/2039 01/01/39 Valid date beyond the year 9999 01/01/10000 Dates with leading or trailing characters 12/31/21/ 31/12/1921AD 31/12/1921.10:55 12/10/2016 8:26:00.39 wfuwdf12/11/74iuhwf fwefew13/11/1974 01/12/1974vdwdfwe 01/01/99werwer 12321301/01/99 Times that look like dates 12:13:56 13:12:01 1:12:01PM 1:12:01 AM Dates that runs across two lines 1/12/19 74 01/12/19 74/13/1946 31/12/20 08:13 Invalid, corrupted or nonsense dates 0/1/2001 1/0/2001 00/01/2100 01/0/2001 0101/2001 01/131/2001 31/31/2001 101/12/1974 56/56/56 00/00/0000 0/0/1999 12/01/0 12/10/-100 74/2/29 12/32/45 20/12/194 2/12-73
/ (?: (?(?&mon_29)) [\/] (? (?&day_29)) | (? (?&mon_30)) [\/] (? (?&day_30)) | (? (?&mon_31)) [\/] (? (?&day_31)) ) [\/] (? [0-9]{4}) (?(DEFINE) (? 0?2 ) (? 0?[469] | (11) ) (? 0?[13578] | 1[02] ) (? 0?[1-9] | [1-2]?[0-9] ) (? 0?[1-9] | [1-2]?[0-9] | 30 ) (? 0?[1-9] | [1-2]?[0-9] | 3[01] ) ) /x
您可以在此版本中按名称检索元素.
say "Month=$+{month} Day=$+{day} Year=$+{year}";
(没有尝试限制年份的值.)
要按以下格式控制日期有效性:
YYYY/MM/DD或YYYY-MM-DD
我建议您使用以下正则表达式:
(((19|20)([2468][048]|[13579][26]|0[48])|2000)[/-]02[/-]29|((19|20)[0-9]{2}[/-](0[4678]|1[02])[/-](0[1-9]|[12][0-9]|30)|(19|20)[0-9]{2}[/-](0[1359]|11)[/-](0[1-9]|[12][0-9]|3[01])|(19|20)[0-9]{2}[/-]02[/-](0[1-9]|1[0-9]|2[0-8])))
火柴
2016-02-29 | 2012-04-30 | 2019年9月31日
非匹配
2016-02-30 | 2012-04-31 | 2019/09/35
如果您只想允许'/'或' - '分隔符,可以自定义它.该RegEx严格控制日期的有效性,并验证28,30和31天月,甚至是29/02月的闰年.
试试吧,它运行良好,防止你的代码出现大量错误!
仅供参考:我为SQL datetime做了一个变种.你会在那里找到它(寻找我的名字):正则表达式来验证时间戳
欢迎反馈:)