【问题标题】:heuristic (fuzzy) date extraction from the string?从字符串中提取启发式(模糊)日期?
【发布时间】:2013-02-27 07:43:04
【问题描述】:

我在启发式解析包含日期但格式相当随意(未知)的文本字符串时遇到问题。

function parseDateStr($text) {
    $cleanText = filter($text);
    # ...
    $day = findDay($cleanText);
    $month = findMonth($cleanText);
    $year = findYear($cleanText);
    # .. assert constraints, parse again or fail
    return sprintf('%04d-%02d-%02d', $year, $month, $day)
}

输入文本是 英语 语言的句子加上任意语法符号(如 \W regexp 类的子集)。该算法的任务是仅在过滤掉任何与日期无关的潜在垃圾(嘈杂)词后提取日期。允许算法失败并且不返回结果。如果在字符串中仅找到两个连接数字 (MM) 和四个其他数字 (YYYY) 的组合 - 假设两个数字对应于日期的月份,并且日期被视为 01(第一天)这个月)。结果以“YYYY-MM-DD”(SQL) 格式(DATE 类型)给出日期。

我的想法是继续使用 preg_replace & co 设计一系列过滤器。此外,对 $year、$day 的范围使用逻辑约束,使用 $month 的词汇表等,但如果可以想到或已经存在类似但更优雅的解决方案或方法,我不会感到惊讶。如果是这样,请让我知道他们。如果能指出任何批评者或潜在的陷阱,我也将不胜感激。

与类似问题的关系:

请注意,该问题与更基本的日期解析问题不同:

因为就我而言,我无法指定或确定字符串的格式。另一方面,以下问题讨论了类似的任务:

我不确定最后一个是否重复,我最终不清楚 OP 想要解析什么(尽管 checkdatedate_parse 似乎是部分有用)。但是关于整个“mokey 业务”的第一个问题也适用于我的案例,并且已通过模糊解析解决,如

dparser.parse("monkey 2010-07-10 love banana",fuzzy=True)

最后,第二个包含了很好的抓取正则表达式(几乎“模糊”)。

PS by elegant 我知道代码相当紧凑(性能没有明显限制,因此可以使用“hacky”正则表达式)。

【问题讨论】:

  • 正如您的一个链接中提到的,您如何解析 1/2/3?我认为您需要解析的字符串示例可能会很有帮助,还是像用户输入并且完全随机?最后,我认为反对 hacky 正则表达式的主要论点通常不是性能(除非针对大字符串运行 多次 次),而是代码维护和容易出现错误。
  • @kjetilh 积分。我将尽快提供示例输入列表以及我的一些解决方案代码。
  • 是的,var_dump(date_parse("Joe Soap 出生于 1981 年 2 月 12 日")); 似乎已经做得很好了。

标签: php regex algorithm date heuristics


【解决方案1】:

时间库

嗯,date_parse 的表现非常非常 非常好,了解为什么 很有教育意义。 PHP 函数 date_parseext/date/libtimelib 的一部分,并且显然(尽管缺乏适当的文档)它在 C 中的实现(由 Derick Rethans 编写并从 Zend Engine 宏部分调用并带有声明) 使它成为一个聪明的工具:

  1. date_parse 已经模糊:文档页面上有很多警告(和抱怨)函数容忍和解析太多,但显然它实际上是一个特性而不是一个错误(否则应该使用 date_parse_from_format 或相应的 DateTime::createFromFormat()
  2. date_parse 以相对智能的方式使用(大量)正则表达式(基于 re2c
  3. 除了过滤这个“扫描器”之外,它还会查找所有可能的单词和日期格式组合(从已知月份和时区列表中),最后,通过查找 YYYY、MM 和DD“单独”(与我需要做的非常相似)。
  4. date_parse 是一个真正编译的“扫描器”,带有前瞻逻辑和错误报告,用户可以进一步处理(没有例外,只有嵌套结果数组中的消息)。
  5. 甚至还有一个 python package 包装了 timelib 的 C 代码(所以我什至不确定在“解析猴子业务”timelibpython-dateutil)

测试和示例

就我而言,我未能从我的数据集中找到任何未被 date_parse 解析的输入示例,即:

echo FuzzyDateParser::fromText('banana 1/2/3');
echo FuzzyDateParser::fromText('Joe Soap was born on 12 February 1981'));
echo FuzzyDateParser::fromText('2005 Feb., reprint'));
echo FuzzyDateParser::fromText('!'); # will fail to parse, producing an empty string.
echo FuzzyDateParser::fromText('monkey 2010-07-10 loves bananas and php');

FuzzyDateParser 类的代码可以在gist 中找到。它可以作为一个模板来处理错误并实现从 date_parse 结果到自己的自定义逻辑的回退(我最终不必为我的案例这样做)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-17
    • 2020-08-14
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多