50

作为我正在从事的一个更大的个人项目的一部分,我试图从各种文本源中分离出内联日期。

例如,我有一个很大的字符串列表(通常采用英语句子或语句的形式),它们采用多种形式:

中央设计委员会会议 10/22 星期二 6:30 pm

Th 9/19 LAB:串行编码(第 2.2 节)

12 月 15 日将有另一场比赛,供今天无法参加的人使用。

工作簿 3(最低工资):截止日期为 9 月 18 日星期三晚上 11:59

他将于 9 月 15 日起飞。

虽然这些日期与自然文本一致,但它们本身都不是特定的自然语言形式(例如,没有“会议将在明天两周后”——都是明确的)。

作为对这种处理没有太多经验的人,最好的起点是什么?我已经研究了诸如dateutil.parsermodule 和parsedatetime之类的东西,但是这些似乎是您隔离了日期之后。

正因为如此,有没有什么好的方法来提取日期和无关的文本

input:  Th 9/19 LAB: Serial encoding (Section 2.2)
output: ['Th 9/19', 'LAB: Serial encoding (Section 2.2)']

或类似的东西?看起来这种处理是由 Gmail 和 Apple Mail 等应用程序完成的,但是可以用 Python 实现吗?

4

7 回答 7

67

我也在寻找解决方案,但找不到任何解决方案,所以我和一个朋友建立了一个工具来做到这一点。我想我会回来分享以防其他人发现它有帮助。

datefinder -- 在文本中查找和提取日期

这是一个例子:

import datefinder

string_with_dates = '''
    Central design committee session Tuesday 10/22 6:30 pm
    Th 9/19 LAB: Serial encoding (Section 2.2)
    There will be another one on December 15th for those who are unable to make it today.
    Workbook 3 (Minimum Wage): due Wednesday 9/18 11:59pm
    He will be flying in Sept. 15th.
    We expect to deliver this between late 2021 and early 2022.
'''

matches = datefinder.find_dates(string_with_dates)
for match in matches:
    print(match)
于 2016-01-28T18:20:06.627 回答
15

我很惊讶没有提到SUTimedateparser 的 search_dates方法。

from sutime import SUTime
import os
import json
from dateparser.search import search_dates

str1 = "Let's meet sometime next Thursday" 

# You'll get more information about these jar files from SUTime's github page
jar_files = os.path.join(os.path.dirname(__file__), 'jars')
sutime = SUTime(jars=jar_files, mark_time_ranges=True)

print(json.dumps(sutime.parse(str1), sort_keys=True, indent=4))
"""output: 
[
    {
        "end": 33,
        "start": 20,
        "text": "next Thursday",
        "type": "DATE",
        "value": "2018-10-11"
    }
]
"""

print(search_dates(str1))
#output:
#[('Thursday', datetime.datetime(2018, 9, 27, 0, 0))]

虽然我尝试过其他模块,如 dateutil、datefinder 和 natty(无法让小鸭与 python 一起工作),但这两个似乎给出了最有希望的结果。

SUTime 的结果更可靠,从上面的代码片段中可以清楚地看出。但是,SUTime 在解析文本等一些基本场景中会失败

“我要到 9/19 才能有空”

或者

“我将在(9 月 18 日至 9 月 20 日)之间没有空。

它没有给出第一个文本的结果,只给出第二个文本的月份和年份。然而,这在 search_dates 方法中处理得很好。search_dates 方法更具侵略性,它将给出与输入文本中的任何单词相关的所有可能日期。

我还没有找到一种方法来严格解析 search_methods 中的日期文本。如果我能找到一种方法来做到这一点,那将是我对 SUTime 的首选,如果我找到它,我也会确保更新这个答案。

于 2018-10-03T22:21:09.487 回答
8

如果您可以识别实际包含日期信息的段,则使用parsedatetime解析它们可能相当简单。不过,有几件事需要考虑,即您的日期没有年份,您应该选择一个语言环境。

>>> import parsedatetime
>>> p = parsedatetime.Calendar()
>>> p.parse("December 15th")
((2013, 12, 15, 0, 13, 30, 4, 319, 0), 1)
>>> p.parse("9/18 11:59 pm")
((2014, 9, 18, 23, 59, 0, 4, 319, 0), 3)
>>> # It chooses 2014 since that's the *next* occurence of 9/18

当您有多余的文本时,它并不总是完美的。

>>> p.parse("9/19 LAB: Serial encoding")
((2014, 9, 19, 0, 15, 30, 4, 319, 0), 1)
>>> p.parse("9/19 LAB: Serial encoding (Section 2.2)")
((2014, 2, 2, 0, 15, 32, 4, 319, 0), 1)

老实说,这似乎是一种足够简单的问题,可以解析特定格式并从每个句子中挑选出最有可能的格式。除此之外,这将是一个不错的机器学习问题。

于 2013-11-15T06:16:56.223 回答
7

您可以将dateutil 模块parse方法与fuzzy选项一起使用。

>>> from dateutil.parser import parse
>>> parse("Central design committee session Tuesday 10/22 6:30 pm", fuzzy=True)
datetime.datetime(2018, 10, 22, 18, 30)
>>> parse("There will be another one on December 15th for those who are unable to make it today.", fuzzy=True)
datetime.datetime(2018, 12, 15, 0, 0)
>>> parse("Workbook 3 (Minimum Wage): due Wednesday 9/18 11:59pm", fuzzy=True)
datetime.datetime(2018, 3, 9, 23, 59)
>>> parse("He will be flying in Sept. 15th.", fuzzy=True)
datetime.datetime(2018, 9, 15, 0, 0)
>>> parse("Th 9/19 LAB: Serial encoding (Section 2.2)", fuzzy=True)
datetime.datetime(2002, 9, 19, 0, 0)
于 2018-07-13T11:25:18.277 回答
1

嗨,我不确定下面的方法是机器学习,但您可以尝试一下:

  • 从外部文本中添加一些上下文,例如文本消息的发布时间、发布时间、现在等(您的文本没有说明年份)
  • 提取所有带有分隔符空白的标记,应该得到如下内容:

    ['Th','Wednesday','9:34pm','7:34','pm','am','9/18','9/','/18', '19','12']
    
  • 使用规则集处理它们,例如从工作日和/或组件形成时间的变化中存在并标记它们,例如'%d:%dpm'、'%d am'、'%d/%d'、'%d/ %d ' 等可能意味着时间。请注意,它可能具有组合,例如“12 / 31”是 3 克('12'、'/'、'31')应该是一个感兴趣的标记“12/31”。

  • “看看”标记的标记周围有什么标记,例如“9:45pm”,例如('Th','9/19','9:45pm')是由“有趣”标记组成的 3gram,并应用可能确定含义的规则.

  • 进行更具体分析的过程,例如,如果有 31/12,则 31 > 12 表示 d/m,反之亦然,但如果有 12/12 m,d 将仅在从文本和/或外部构建的上下文中可用。

干杯

于 2013-11-15T08:48:25.553 回答
1

较新版本的parsedatetimelib 提供搜索功能。

例子

from dateparser.search import search_dates

dates = search_dates('Central design committee session Tuesday 10/22 6:30 pm')
于 2019-09-10T21:23:34.437 回答
0

没有任何完美的解决方案。它完全取决于您应该使用哪种类型的数据。通过手动检查某些数据集并准备正则表达式模式并测试它是否有效,可以快速查看和分析数据。

预定义的所有包在一定程度上解决了一个日期提取问题,并且是有限的。如果可以通过查看数据大致找出模式,那么用户可以准备正则表达式。这将帮助他们防止对包中编写的所有规则进行迭代和循环。

于 2021-05-07T10:50:07.630 回答