python 提取文字段落中的日期字符串

需求

  • 在日常业务开发中常常会碰到需要从一段文字中提取时间的情况。例如从文字中提取发布时间、创建时间等。针对不同的文字情况、不同的时间格式,这里整理一份关于提取大部分文字段落中日期时间的代码。有需要的直接调用即可。

输入

  • 需要识别的文字段,例如从“技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022-09-21发布”提取日期。

安装库

pip install chardet -i https://pypi.douban.com/simple/

格式

  • 这里自定义需要提取出来后的时间格式:年-月-日 时:分:秒(%Y-%m-%d %H:%M:%S),
    即base_date=‘2020-01-01 00:00:00’,可以根据自己的格式修改为自己想要的格式。

定义正则匹配

# 正则中的%s分割
splits = [
    {1: [('年', '月', '日', '点', '分', '秒'), ('-', '-', '', ':', ':', ''), ('\/', '\/', '', ':', ':', ''),
         ('\.', '\.', '', ':', ':', '')]},
    {2: [('年', '月', '日', '点', '分'), ('-', '-', '', ':', ''), ('\/', '\/', '', ':', ''), ('\.', '\.', '', ':', '')]},
    {3: [('年', '月', '日'), ('-', '-', ''), ('\/', '\/', ''), ('\.', '\.', '')]},
    {4: [('年', '月', '日'), ('-', '-', ''), ('\/', '\/', ''), ('\.', '\.', '')]},

    {5: [('月', '日', '点', '分', '秒'), ('-', '', ':', ':', ''), ('\/', '', ':', ':', ''), ('\.', '', ':', ':', '')]},
    {6: [('月', '日', '点', '分'), ('-', '', ':', ''), ('\/', '', ':', ''), ('\.', '', ':', '')]},
    {7: [('月', '日'), ('-', ''), ('\/', ''), ('\.', '')]},

    {8: [('点', '分', '秒'), (':', ':', '')]},
    {9: [('点', '分'), (':', '')]},
]

# 匹配正则表达式
matchs = {
    1: (r'\d{4}%s\d{1,2}%s\d{1,2}%s \d{1,2}%s\d{1,2}%s\d{1,2}%s', '%%Y%s%%m%s%%d%s %%H%s%%M%s%%S%s'),
    2: (r'\d{4}%s\d{1,2}%s\d{1,2}%s \d{1,2}%s\d{1,2}%s', '%%Y%s%%m%s%%d%s %%H%s%%M%s'),
    3: (r'\d{4}%s\d{1,2}%s\d{1,2}%s', '%%Y%s%%m%s%%d%s'),
    4: (r'\d{2}%s\d{1,2}%s\d{1,2}%s', '%%y%s%%m%s%%d%s'),

    # 没有年份
    5: (r'\d{1,2}%s\d{1,2}%s \d{1,2}%s\d{1,2}%s\d{1,2}%s', '%%m%s%%d%s %%H%s%%M%s%%S%s'),
    6: (r'\d{1,2}%s\d{1,2}%s \d{1,2}%s\d{1,2}%s', '%%m%s%%d%s %%H%s%%M%s'),
    7: (r'\d{1,2}%s\d{1,2}%s', '%%m%s%%d%s'),

    # 没有年月日
    8: (r'\d{1,2}%s\d{1,2}%s\d{1,2}%s', '%%H%s%%M%s%%S%s'),
    9: (r'\d{1,2}%s\d{1,2}%s', '%%H%s%%M%s'),
}

编写提取逻辑

parten_other = '\d+天前|\d+分钟前|\d+小时前|\d+秒前'

class TimeFinder(object):

    def __init__(self, base_date=None):
        self.base_date = base_date
        self.match_item = []

        self.init_args()
        self.init_match_item()

    def init_args(self):
        # 格式化基础时间
        if not self.base_date:
            self.base_date = datetime.now()
        if self.base_date and not isinstance(self.base_date, datetime):
            try:
                self.base_date = datetime.strptime(self.base_date, '%Y-%m-%d %H:%M:%S')
            except Exception as e:
                raise Exception('type of base_date must be str of%Y-%m-%d %H:%M:%S or datetime')

    def init_match_item(self):
        # 构建穷举正则匹配公式 及提取的字符串转datetime格式映射
        for item in splits:
            for num, value in item.items():
                match = matchs[num]
                for sp in value:
                    tmp = []
                    for m in match:
                        tmp.append(m % sp)
                    self.match_item.append(tuple(tmp))

    def get_time_other(self, text):
        m = re.search('\d+', text)
        if not m:
            return None
        num = int(m.group())
        if '天' in text:
            return self.base_date - timedelta(days=num)
        elif '小时' in text:
            return self.base_date - timedelta(hours=num)
        elif '分钟' in text:
            return self.base_date - timedelta(minutes=num)
        elif '秒' in text:
            return self.base_date - timedelta(seconds=num)

        return None

    def find_time(self, text):
        # 格式化text为str类型
        if isinstance(text, bytes):
            encoding = chardet.detect(text)['encoding']
            text = text.decode(encoding)

        res = []
        parten = '|'.join([x[0] for x in self.match_item])

        parten = parten + '|' + parten_other
        match_list = re.findall(parten, text)
        if not match_list:
            return None
        for match in match_list:
            for item in self.match_item:
                try:
                    date = datetime.strptime(match, item[1].replace('\\', ''))
                    if date.year == 1900:
                        date = date.replace(year=self.base_date.year)
                        if date.month == 1:
                            date = date.replace(month=self.base_date.month)
                            if date.day == 1:
                                date = date.replace(day=self.base_date.day)
                    res.append(datetime.strftime(date, '%Y-%m-%d %H:%M:%S'))
                    break
                except Exception as e:
                    date = self.get_time_other(match)
                    if date:
                        res.append(datetime.strftime(date, '%Y-%m-%d %H:%M:%S'))
                        break
        if not res:
            return None
        return res

执行入口

def handleDate(time_str):
    result = None
    # 定义日期格式
    timefinder = TimeFinder(base_date='2020-01-01 00:00:00')
    parsed_time = timefinder.find_time(time_str.replace("\t", "").replace("\n", ""))
    if parsed_time is None:
        if time_str.find("年") >= 0:
            parsed_time = timefinder.find_time(time_str.replace(" ", "").replace("\t", ""))
            if parsed_time is not None:
                result = parsed_time[0]
    else:
        result = parsed_time[0]
    return result

测试

if __name__ == '__main__':
    test1 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022-09-21发布"
    test2 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022/09/21发布"
    test3 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022-9-21发布"
    test4 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022-09-21 08:01发布"
    test5 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022-09-21 08:01:01发布"
    test6 = "技术总是要日积月累的,我是技术空间,欢迎关注我。此文章2022年9月21日发布"
    print(test1 + " -> " + handleDate(test1))
    print(test2 + " -> " + handleDate(test2))
    print(test3 + " -> " + handleDate(test3))
    print(test4 + " -> " + handleDate(test4))
    print(test5 + " -> " + handleDate(test5))
    print(test6 + " -> " + handleDate(test6))

在这里插入图片描述

此方法可以识别大部分文字段落中带有日期字符串的日期,日期必须是数字日期,不可是大写的,“一月”、“二零二二年”之类的识别不了。

关注我,坚持每日积累一个技巧,长期坚持,我们将会不断进步。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code_space

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值