当数据有点乱时使用 datetime.strptime :额外的空格,一月或一月

问题描述

目前我正在处理的文本是具有某种标准格式的日期,但是数据不是非常干净。

例如,文本可以采用以下格式:

Jan. 1,2021 (dot after Jan)
Jan,1 2021 (comma after Jan)
January,1 2020 (Full month with comma)
Jan,1 2020 (two spaces after Jan,instead of one)

我不太确定如何处理这个问题。 我想将这些字符串转换2021-01-01 格式。

我的计划是先转换为日期时间对象,然后再转换回字符串。

然而,当使用 strptime 时,模式似乎需要是刚性的, 并且不允许使用正则表达式之类的模式。

print(datetime.datetime.strptime(timestamp,'%b %d,%Y'))

而不是像 '%b|%B\s[.,]?

有人对如何将我的文本转换为年-月-日格式有任何建议吗?

解决方法

您可以尝试使用 dateutil 库,(它是下载次数最多的 pypi 包之一)

>>> from dateutil import parser
>>>
>>> print(parser.parse("Jan. 1,2021"))
2021-01-01 00:00:00
>>>
>>> print(parser.parse("Jan,1 2021"))
2021-01-01 00:00:00
>>>
>>> print(parser.parse("January,1 2020"))
2020-01-01 00:00:00
>>>
>>> print(parser.parse("Jan,1 2020"))
2020-01-01 00:00:00
,

这是一个适用于您提供的案例的正则表达式。

import re

pattern = """(?ix)   # ignore case,verbose
   (?P<month>
        jan(uary)?
       |feb(uary)?
       |mar(ch)?
       |apr(il)?
       |may
       |jun(e)?
       |jul(y)?
       |aug(ust)?
       |sep(tember)?
       |oct(ober)?
       |nov(ember)?
       |dec(ember)?
   )
   \D+
   (?P<day>\d(\d)?)
   \D+
   (?P<year>\d\d(\d\d)?)
"""

regex = re.compile(pattern)

testcases = """
Jan. 1,2021 (dot after Jan)
Jan,1 2021 (comma after Jan)
January,1 2020 (Full month with comma)
Jan,1 2020 (two spaces after Jan,instead of one)
""".strip().splitlines()

for test in testcases:
    print(test,end=' => ')
    m = regex.search(test)
    if m:
        print(m.groupdict())
    else:
        print(m)

输出:

Jan. 1,2021 (dot after Jan) => {'month': 'Jan','day': '1','year': '2021'}
Jan,1 2021 (comma after Jan) => {'month': 'Jan','year': '2021'}
January,1 2020 (Full month with comma) => {'month': 'January','year': '2020'}
Jan,instead of one) => {'month': 'Jan','year': '2020'}

也就是说,使用 foxyblue 建议的 dateutil 库可能更健壮。

,

如果你不使用图书馆,你可能会有点粗鲁:

def normalise(date):
    month_name,day,year = date.replace(',','').split()
    short_month_name = month_name[:3]
    return f'{short_month_name} {day} {year}'

用法:

>>> normalise('January,1 2020')
'Jan 1 2020'

然后就可以正常用datetime解析了。