检查字符串是否包含日期,任何格式
- 2025-03-07 09:00:00
- admin 原创
- 28
问题描述:
如何检查字符串是否可以解析为日期?
1990 年 1 月 19 日
1990 年 1 月 19 日
1990年1月19日
1990 年 1 月 19 日
1990 年 1 月 19 日
1990
1990 年 1 月
1990年1月
这些都是有效日期。如果担心第 3 项和上面最后一项之间的空格不足,可以通过在字母/字符和数字之间自动插入空格(如果需要)轻松解决。
首先,我们来了解一下基础知识:
我尝试将其放入if statement
:
if datetime.strptime(item, '%Y') or datetime.strptime(item, '%b %d %y') or datetime.strptime(item, '%b %d %Y') or datetime.strptime(item, '%B %d %y') or datetime.strptime(item, '%B %d %Y'):
但这是在 try-except 块中,并且一直返回如下内容:
16343 time data 'JUNE1890' does not match format '%Y'
除非,它满足声明中的第一个条件if
。
需要澄清的是,我实际上并不需要日期的值 - 我只是想知道它是否是。理想情况下,它应该是这样的:
if item is date:
print date
else:
print "Not a date"
有什么办法可以做到这一点?
解决方案 1:
该parse
函数dateutils.parser
能够将多种日期字符串格式解析为datetime
对象。
pip install python-dateutil
如果您只是想知道某个字符串是否可以表示或包含有效日期,可以尝试以下简单函数:
from dateutil.parser import parse
def is_date(string, fuzzy=False):
"""
Return whether the string can be interpreted as a date.
:param string: str, string to check for date
:param fuzzy: bool, ignore unknown tokens in string if True
"""
try:
parse(string, fuzzy=fuzzy)
return True
except ValueError:
return False
然后你有:
>>> is_date("1990-12-1")
True
>>> is_date("2005/3")
True
>>> is_date("Jan 19, 1990")
True
>>> is_date("today is 2019-03-27")
False
>>> is_date("today is 2019-03-27", fuzzy=True)
True
>>> is_date("Monday at 12:01am")
True
>>> is_date("xyz_not_a_date")
False
>>> is_date("yesterday")
False
自定义解析
parse
可能会将某些字符串识别为日期,但您并不想将其视为日期。例如:
解析
"12"
并将"1999"
返回一个日期时间对象,该对象表示当前日期,其中日期和年份替换字符串中的数字"23, 4"
并将"23 4"
被解析为datetime.datetime(2023, 4, 16, 0, 0)
。"Friday"
将返回未来最近星期五的日期。同样
"August"
对应于当前日期,但月份更改为八月。
并且parse
不具备语言环境意识,因此无法识别除英语之外的其他语言中的月份或星期几。
这两个问题都可以通过使用自定义类来在一定程度上解决parserinfo
,该类定义了如何识别月份和日期名称:
from dateutil.parser import parserinfo
class CustomParserInfo(parserinfo):
# three months in Spanish for illustration
MONTHS = [("Enero", "Enero"), ("Feb", "Febrero"), ("Marzo", "Marzo")]
然后可以使用此类的实例parse
:
>>> parse("Enero 1990")
# ValueError: Unknown string format
>>> parse("Enero 1990", parserinfo=CustomParserInfo())
datetime.datetime(1990, 1, 27, 0, 0)
解决方案 2:
如果您想解析这些特定格式,您只需匹配格式列表即可:
txt='''\nJan 19, 1990
January 19, 1990
Jan 19,1990
01/19/1990
01/19/90
1990
Jan 1990
January1990'''
import datetime as dt
fmts = ('%Y','%b %d, %Y','%b %d, %Y','%B %d, %Y','%B %d %Y','%m/%d/%Y','%m/%d/%y','%b %Y','%B%Y','%b %d,%Y')
parsed=[]
for e in txt.splitlines():
for fmt in fmts:
try:
t = dt.datetime.strptime(e, fmt)
parsed.append((e, fmt, t))
break
except ValueError as err:
pass
# check that all the cases are handled
success={t[0] for t in parsed}
for e in txt.splitlines():
if e not in success:
print e
for t in parsed:
print '"{:20}" => "{:20}" => {}'.format(*t)
印刷:
"Jan 19, 1990 " => "%b %d, %Y " => 1990-01-19 00:00:00
"January 19, 1990 " => "%B %d, %Y " => 1990-01-19 00:00:00
"Jan 19,1990 " => "%b %d,%Y " => 1990-01-19 00:00:00
"01/19/1990 " => "%m/%d/%Y " => 1990-01-19 00:00:00
"01/19/90 " => "%m/%d/%y " => 1990-01-19 00:00:00
"1990 " => "%Y " => 1990-01-01 00:00:00
"Jan 1990 " => "%b %Y " => 1990-01-01 00:00:00
"January1990 " => "%B%Y " => 1990-01-01 00:00:00
解决方案 3:
流行的 Python 库pandas
中有一个内置函数,可以相当一致地解析日期。如果其参数为errors='coerce'
,它也可以返回非日期字符串的 NaN。
txt='''\nJan 19, 1990
January 19, 1990
Jan 19,1990
01/19/1990
01/19/90
1990
Jan 1990
January1990
19 Jan 1990
this is not date'''
for s in txt.split('
'):
dt = pd.to_datetime(s.replace(',', ' '), errors='coerce')
print(dt, dt == dt)
# 1990-01-19 00:00:00 True
# 1990-01-19 00:00:00 True
# 1990-01-19 00:00:00 True
# 1990-01-19 00:00:00 True
# 1990-01-19 00:00:00 True
# 1990-01-01 00:00:00 True
# 1990-01-01 00:00:00 True
# 1990-01-01 00:00:00 True
# 1990-01-19 00:00:00 True
# NaT False
它的优点在于pd.to_datetime
它是矢量化的,因此可以将整个列表传递给它。
converted = pd.to_datetime(txt.split('
'), errors='coerce')
要返回布尔系列,请notna()
调用结果。
converted.notna()