Python findall returns 意想不到的结果

Python findall returns unexpected results

我是 Python 的新人,但必须制作一个正则表达式来获取 dd-mm-yyyy 格式文本格式的日期。我写了这样的东西:

format1 = re.findall('[0-2][0-9]-02-(\d){4}|(([0-2][0-9]|30)-(04|06|09|11)-(\d){4})|(([0-2][0-9]|30|31)-(01|03|05|07|08|10|12)-(\d){4})',article)

它还会检查日期格式是否正确。我检查了它是否适用于 pythex.org 我 return 是正确的日期,但不幸的是还有一些空匹配和随机数:

Match 1
1.  None
2.  None
3.  None
4.  None
5.  None
6.  21-10-2005
7.  21
8.  10
9.  5

Match 2
1.  None
2.  None
3.  None
4.  None
5.  None
6.  31-12-1993
7.  31
8.  12
9.  3

如何将正则表达式改进为 return 仅日期或删除非日期的所有内容?

在我看来你需要使用 非捕获组

事情是这样的:在正则表达式中,括号 () 内的任何内容都是 捕获的组 - 它作为匹配中捕获的项目之一出现。

如果您想使用括号对模式的一部分进行分组(例如,以便您可以在低于顶层的地方使用 |),但您 希望括号内的文本在匹配输出中成为单独的项目,那么你想使用 非捕获 组。

要做到这一点,您应该使用 (foo),而不是使用 (?:foo) - 在开头添加 ?:。这会阻止该组在最后一场比赛中捕获文本。

Amber 的建议非常好。但我可以提个建议吗?尽量不要将所有逻辑都塞进正则表达式本身。它使它几乎不可读,并且仍然没有按照书面处理极端情况(例如,它接受每年的 2 月 29 日,而不仅仅是闰年)。不要使用正则表达式来完成真正的解析器的工作。

相反,搜索通用格式,然后使用专用日期解析代码对其进行解析,如果通过解析,则保留它。例如:

import datetime, re

def is_valid_dmy_date(datestr):
    try:
        datetime.datetime.strptime(datestr, '%d-%m-%Y')
    except ValueError:
        return False
    return True

# In Python 3, wrap filter call in list() if you need a real list,
# or just iterate results of filter directly if that's all you need
all_dates = filter(is_valid_dmy_date, re.findall(r'\b\d\d-\d\d-\d{4}\b', article))

您会注意到,正则表达式已大大简化(我添加了 \b 零宽度断言,因此它不会匹配 001-01-200123 之类的东西,但如果应该匹配日期,您可以删除它们即使没有单词边界)。工作被传递给 datetime.strptime,它知道真正的日期,因此它正确地拒绝了像 2011 年 2 月 29 日这样的东西。

re.findallreturns 包含所有结果的元组 () 捕获。您的常规模式中有 9 (),因此您得到了一个包含 9 个元素的元组。 尝试 print format1[0][5] 可能会解决这种情况下的问题 或使用 re.search 代替
format1 = re.search('[0-2][0-9]-02-(\d){4}|(([0-2][0-9]|30)-(04|06|09|11)-(\d){4})|(([0-2][0-9]|30|31)-(01|03|05|07|08|10|12)-(\d){4})',article) print format1.group(0)