Python findall返回意外结果

时间:2015-10-28 00:39:29

标签: python regex date findall

我是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 我返回正确的日期,但不幸的是还有一些空的匹配和随机数字:

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

如何改进正则表达式以仅返回日期或删除不是日期的所有内容?

3 个答案:

答案 0 :(得分:3)

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

这就是事情:在正则表达式中,括号()内的任何内容都是捕获的组 - 它是匹配中捕获的项目之一。< / p>

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

要做到这一点,您将拥有(foo),而是使用(?:foo) - 将?:添加到开头。这可以防止该组在最终匹配中捕获文本。

答案 1 :(得分:1)

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日这样的东西。

答案 2 :(得分:1)

re.findall返回一个包含所有结果()捕获的元组。你的常规模式中有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)