从字符串中提取启发式(模糊)日期?

时间:2013-03-11 23:03:46

标签: php regex algorithm date heuristics

我有一个问题,启发式地解析一个包含日期但是以相当任意(未知)格式的文本字符串。

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 & amp;来设计一系列过滤器。合。此外,在$ year,$ day的范围内使用逻辑约束,使用$ month的词汇等等,但如果可以想到或已经存在类似但更优雅的解决方案或方法,我不会感到惊讶。如果是这样,请让我知道他们。如果可以指出任何评论家或潜在的陷阱,我也将不胜感激。

与类似问题的关系:

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

因为在我的情况下我无法指定或确定字符串的格式。另一方面,以下问题涉及类似的任务:

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

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

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

PS 优雅我理解代码相当紧凑(性能没有明显限制,所以使用“hacky”regexp就可以了)。

1 个答案:

答案 0 :(得分:4)

timelib

嗯, date_parse 表现良好非常非常,学习为什么非常有教育意义。 PHP函数date_parseext/date/lib timelib 的一部分,显然(尽管缺少适当的文档)它在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 是一个真正的编译“扫描程序”,它带有可由用户进一步处理的预见逻辑和错误报告(没有例外,只是嵌套结果数组中的消息)。 / LI>
  5. 甚至有一个python package包装了timelib的C代码(所以我甚至不确定哪个在“解析猴子业务” timelib python-中最终更好dateutil
  6. 测试和示例

    就我而言,我未能从我的数据集中找到任何未被 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');
    

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