一个"智能"(宽容)日期解析器?

Jea*_*uys 5 regex perl parsing date

我必须将一个非常大的数据集从一个系统迁移到另一个系统.其中一个"源"列包含日期,但实际上是一个没有约束的字符串,而目标系统要求格式为yyyy-mm-dd的日期.

许多(但不是全部)源日期格式为yyyymmdd.所以为了强制它们达到预期的格式,我做(在Perl中):

return "$1-$2-$3" if ($val =~ /(\d{4})[-\/]*(\d{2})[-\/]*(\d{2})/);
Run Code Online (Sandbox Code Playgroud)

当源日期远离"通用"yyyymmdd时出现问题.目标是在放弃之前尽可能多地挽救日期.示例源字符串包括:

21/3/1998,2004年3月,2001年,3/4/97

我可以尝试通过一系列正则表达式(如上面的表达式)来匹配尽可能多的示例.

但有更聪明的事情吗?我不是在重新发明轮子吗?在某个地方有类似的东西吗?我找不到任何相关的谷歌搜索"原谅日期解析器".(任何语言都可以).

Jea*_*uys 2

我最终提取了一个包含数据集中实际出现的 200 多个日期示例的测试集。有些人行为轻微,有些人则完全生病了(例如“01010”)。

我尝试了所有能找到的现有 Perl 模块,但成功率太低。我最终重新发明了轮子,取得了超过 98% 的成功率。

我的算法是一系列越来越模糊的识别器,从严格有效的日期开始一直到总猜测范围。第一个返回“成功”结果的人获胜。在该堆栈的中间,我有“主”识别器,它执行以下操作:

  • 解析字符串中任意位置的数字集。法语和英语的“月份名称”也得到认可。

  • 对于每个人,我将它们分为三个部分:年度候选人、月份候选人、日候选人。例如,“13”将位于“可能的年份”存储桶中和“可能的日期”存储桶中。当然,“二月”只会出现在“月份”桶中。在每个存储桶中,该值都标有“合理性级别”,这是一个取决于许多因素的任意数字。例如,将 2010 年作为年份比 10 更合理。

  • 查看三个桶中的每一个。如果其中任何一个只有一项,则它是该存储桶的。它也从其他存储桶中删除。

  • 按顺序(年、月、日)查找各自存储桶中剩余的缺失值,并选取最合理的值。如果出现平局,则取字符串中最后出现的那个(实际上,那些的可信度稍高)。该规则将于 2010 年 7 月 3 日即 3 月 7 日失效,正如我在法国所需要的那样。如果情况适用,请从其他存储桶中删除该值。

  • 如果缺少任何值,请使用默认值(例如,我使用 8191 作为默认年份,这是我的目标系统中允许的最大值)。

整个事情是非常启发式的,但符合我的要求,即拥有垃圾比丢失信息更好。