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.findall
returns 包含所有结果的元组 ()
捕获。您的常规模式中有 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)
我是 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.findall
returns 包含所有结果的元组 ()
捕获。您的常规模式中有 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)