我正在研究一个python程序的正则表达式,它应该找到所有日期出现在文本中。
根据作业的描述,唯一有效的日期格式如下:
“3/30/18”,“3/30/2018”,“3-30-2018”,“03-30-2018”,“30.3.2018”, “30. 3. 2018”,“2018-03-30”
我创建了一个包含有效格式的字符串变量,并添加了一些以检查我的代码是否可行。
text_string = 'Examples for valid dates include "3/30/18", "3/30/2018",
"3-30-2018", "03-30-2018", "30.3.2018", "30. 3. 2018", "2018-03-30",
"3/30/1", "3/30/201", "/30/18", "3//18", "3/ /18", "3/30/", "3/301/18"'
以下是我提出的正则表达式:
match_string = re.findall('(?:\d{1,2}/\s*\d{1,2}/\s*\d{2,4})|
(?:\d{1,2}-\s*\d{1,2}-\s*\d{2,4})|(?:\d{4}-\s*\d{1,2}-\s*\d{1,2})|
(?:\d{1,2}.\s*\d{1,2}.\s*\d{4})', text_string)
显然,我的代码会捕获上面列出的所有7种有效日期格式,但它也返回“3/30/201”,这不应该是有效日期。
我试图在我的代码中添加'$',但它只是搞砸了更多,所以我想知道如何纠正我的代码来解决这个问题。
P.S。这是一个Regex赋值,我不允许使用'datetime'T_T
答案 0 :(得分:1)
正则表达式中有问题的部分是:
\d{2,4}
这匹配2到4位数 - 这意味着3位数也被视为有效年份。如果将\d{2,4}
的两个出现替换为\d{2}(?:\d{2})?)\b
,则正则表达式可以正常工作:
(?:\d{1,2}/\s*\d{1,2}/\s*\d{2}(?:\d{2})?)\b|(?:\d{1,2}-\s*\d{1,2}-\s*\d{2}(?:\d{2})?)\b|(?:\d{4}-\s*\d{1,2}-\s*\d{1,2})|(?:\d{1,2}.\s*\d{1,2}.\s*\d{4})
(不要忘记使用原始字符串文字来定义正则表达式:r'(?:\d{1,2}/\s*\d{1,2}/\s*\d{2}(?:\d{2})?)\b|(?:\d{1,2}-\s*\d{1,2}-\s*\d{2}(?:\d{2})?)\b|(?:\d{4}-\s*\d{1,2}-\s*\d{1,2})|(?:\d{1,2}.\s*\d{1,2}.\s*\d{4})'
)
输出:
['3/30/18', '3/30/2018', '3-30-2018', '03-30-2018', '30.3.2018', '30. 3. 2018', '2018-03-30']
\d{2}(?:\d{2})?)\b
正好匹配2位或4位数字 - \b
边界是断言不再有数字,否则它仍会考虑" 3/30 / 201"是一个有效的日期。
最后,正则表达式可以更简洁地写成
\b\d{1,2}([-/]|\. ?)\d{1,2}\1\d{2}(?:\d{2})?\b|\b\d{4}-\d{2}-\d{2}\b
这使用捕获组断言没有混合分隔符(如3-2.2018
)并且空格是一致的(因此1. 2.2018
之类的东西不匹配)。