如何使用Python 3.x从字符串中提取日期

时间:2017-07-13 12:11:59

标签: python python-3.x date

我需要使用Python 3.4从SMS中找出电话帐单截止日期我已经使用了dateutil.parser和datefinder,但根据我的用例没有成功。

示例:sms_text ="您的电话帐单已经发送到您的regd电子邮件地址abc@xyz.com,该电话帐单是17月20日到期的Rs.72.23的Jun 17。请检查收件箱"

代码1:

import datefinder
due_dates = datefinder.find_dates(sms_text)
for match in due_dates:
    print(match)

结果:2017-07-17 00:00:00

代码2:

import dateutil.parser as dparser
due_date = dparser.parse(sms_text,fuzzy=True)
print(due_date)

结果:ValueError可能是因为文本中有多个日期

如何从此类文本中选择截止日期?日期格式不固定,但文本中将有2个日期:一个是生成账单的月份,另一个是截止日期,顺序相同。即使我得到一个正则表达式来解析文本,也会很棒。

更多示例文本:

  1. 您好!您的未结算电话是293.72到期日为7月3日。
  2. 比尔日期为06-JUN-17,因为您的电话号码为1234567890
  3. 比尔日期为06-JUN-17,为219卢比,将于7月5日到期,电话号码为1234567890
  4. 截至27日 - 6月17日,您的运营商固定电话/宽带ID 1234567890的电子邮件已发送至aby@xyz.com,电子邮件地址为xyz@abc.com。到期金额:3,764.53卢比,截止日期:17-Jul-17。
  5. 电话号码日期为2017年6月21日的法案详情。 1234567890:到期总额:374.12卢比,截止日期:2017年7月9日,账单交付日期:2017年6月25日,
  6. 问候!您的手机账单1234567890,dtd 18-Jun-17,付款到期日06-Jul-17已发送至abc@xyz.com
  7. 尊敬的客户,您的电话费为Rs.191.24,应于2017年6月25日到期
  8. 嗨!您的电话费用为卢比。 560.41将于03-07-2017到期。

4 个答案:

答案 0 :(得分:2)

使用var dt = $("#myTable").DataTable({ dom: "lfrtip" // i = info, indicates DOM order paging: false // to turn off default is true }); 的想法:

dateutil.parser

答案 1 :(得分:0)

为什么不使用regex?如果您的输入字符串始终包含此子字符串due on ... has been,您可以执行以下操作:

import re
from datetime import datetime

string = """Your phone bill for Jun'17 of Rs.72.23 due on 15-07-2017 has been
 sent to your regd email ID abc@xyz.com. Pls check Inbox"""

match_obj = re.search(r'due on (.*) has been', string)

if match_obj:
    date_str = match_obj.group(1)
else:
    print "No match!!"
try:
    # DD-MM-YYYY
    print datetime.strptime(date_str, "%d-%m-%Y")
except ValueError:
    # try another format
    try:
        print datetime.strptime(date_str, "%Y-%m-%d")
    except ValueError:
        try:
            print datetime.strptime(date_str, "%m-%d")
        except ValueError:
            ...

答案 2 :(得分:0)

以短信作为示例提供:

sms_text = "Your phone bill for Jun'17 of Rs.72.23 due on 15-07-2017 has been sent to your regd email ID abc@xyz.com. Pls check Inbox"

可以在regex模块中使用pythons构建来匹配字符串的'due on'和'has been'部分。

import re

sms_text = "Your phone bill for Jun'17 of Rs.72.23 due on 15-07-2017 has been sent to your regd email ID abc@xyz.com. Pls check Inbox"

due_date = re.split('due on', re.split('has been', sms_text)[0])[1]

print(due_date)

结果:1​​5-07-2017

使用此示例时,日期格式无关紧要,但重要的是将字符串拆分的单词保持一致。

答案 3 :(得分:0)

有两件事阻止datefinder正确解析您的样本:

  1. 账单金额:数字被解释为年份,因此如果他们有3或4位数字,则会创建日期
  2. datefinder定义为分隔符的字符可能会阻止查找合适的日期格式(在本例中为':'
  3. 我们的想法是首先删除文本中阻止datefinder识别所有日期的部分文本。不幸的是,这是一个尝试和错误,因为这个包使用的正则表达式对我来说太大了,无法彻底分析。

    def extract_duedate(text):
        # Sanitize the text for datefinder by replacing the tricky parts 
        # with a non delimiter character
        text = re.sub(':|Rs[\d,\. ]+', '|', text, flags=re.IGNORECASE)
    
        return list(datefinder.find_dates(text))[-1]
    

    Rs[\d,\. ]+会删除帐单金额,因此不会将其视为日期的一部分。它将匹配'Rs[.][ ][12,]345[.67]'形式的字符串(实际上更多变体,但这只是为了说明)。

    显然,这是一个原始的示例函数。 以下是我得到的结果:

    1 : 2017-07-03 00:00:00
    2 : 2017-06-06 00:00:00 # Wrong result: first date instead of today
    3 : 2017-07-05 00:00:00
    4 : 2017-07-16 00:00:00
    5 : 2017-06-25 00:00:00
    6 : 2017-07-06 00:00:00
    7 : 2017-06-25 00:00:00
    8 : 2017-03-07 00:00:00
    

    样本2存在一个问题:datefinder

    无法单独识别“今天”

    示例:

    >>> list(datefinder.find_dates('Rs 219 is due today'))
    [datetime.datetime(219, 7, 13, 0, 0)]
    >>> list(datefinder.find_dates('is due today'))
    []
    

    因此,为了处理这种情况,我们可以简单地将令牌'today'替换为当前日期作为第一步。这将提供以下功能:

    def extract_duedate(text):
        if 'today' in text:
            text = text.replace('today', datetime.date.today().isoformat())
    
        # Sanitize the text for datefinder by replacing the tricky parts 
        # with a non delimiter character
        text = re.sub(':|Rs[\d,\. ]+', '|', text, flags=re.IGNORECASE)
    
        return list(datefinder.find_dates(text))[-1]
    

    现在结果对所有样品都有好处:

    1 : 2017-07-03 00:00:00
    2 : 2017-07-18 00:00:00 # Well, this is the date of my test
    3 : 2017-07-05 00:00:00
    4 : 2017-07-16 00:00:00
    5 : 2017-06-25 00:00:00
    6 : 2017-07-06 00:00:00
    7 : 2017-06-25 00:00:00
    8 : 2017-03-07 00:00:00
    

    如果需要,可以让函数返回所有日期,它们都应该是正确的。