识别任意日期字符串

Joe*_*oel 22 java date classification

我需要能够识别日期字符串.如果我无法区分月份和日期(例如12/12/10)并不重要,我只需要将字符串分类为日期,而不是将其转换为Date对象.所以,这实际上是一个分类而不是解析问题.

我会有一些文字,例如:

"bla bla bla bla 12 Jan 09 bla bla bla 01/04/10 bla bla bla"

我需要能够识别每个日期字符串的开始和结束边界.

我想知道是否有人知道任何可以做到这一点的java库.到目前为止,我的google-fu还没有提出任何建议.

更新:我需要能够识别出最广泛的表示日期的方法.当然,天真的解决方案可能是为每种可想到的格式编写一个if语句,但是模式识别方法,使用训练有素的模型,理想情况下是我所追求的.

Boz*_*zho 5

您可以在Java中循环所有可用的日期格式:

for (Locale locale : DateFormat.getAvailableLocales()) {
    for (int style =  DateFormat.FULL; style <= DateFormat.SHORT; style ++) {
        DateFormat df = DateFormat.getDateInstance(style, locale);
        try {
                df.parse(dateString);
                // either return "true", or return the Date obtained Date object
        } catch (ParseException ex) {
            continue; // unperasable, try the next one
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会考虑任何自定义日期格式.


Pus*_*jee 5

使用JChronic

您可能希望使用edu.mit.broad.genome.utils包中的DateParser2.


dar*_*ioo 5

可能有助于您完成任务的规则:

  1. 制作或查找某种具有匹配月份的已知单词的数据库.缩写和全名,如JanJanuary.搜索时,它必须不区分大小写,因为fEBruaRy也是一个月,虽然输入它的人一定是醉了.如果你打算搜索非英语月份,还需要一个数据库,因为没有启发式的工具会发现"Wrzesień"在9月份已经很好了.
  2. 仅限英语,查看序号,并为数字1到31建立数据库.这些数据将在数天和数月内有用.如果您想将此方法用于其他语言,那么您将不得不进行自己的研究.
  3. 再一次,仅限英语,分别检查"Anno Domini"和"Before Christ",即AD和BC.它们也可以是AD和BC形式
  4. 关于代表天,月和年的数字本身,您必须知道您的限制在哪里.是0-9999还是更多?也就是说,您想搜索代表9999年以后年份的日期吗?如果不是,那么具有1-4个连续数字的字符串对于有效的日,月或年是好的猜测.
  5. 天和月有一个或两个数字.前导零是可以接受的,因此格式为0*,其中*可以是1-9的字符串是可接受的.
  6. 分隔符可能很棘手,但如果你不允许像10/20\1999这样的格式不一致,那么你将为自己省去很多悲伤.这是因为10*20*1999可以是有效日期,*通常是集合的一个元素{-,_, ,:,/,\,.,','},但*可能是上述集合中2或3个元素的组合.您必须再次选择可接受的分隔符.10?20?1999可能是一个有着奇怪优雅感的人的有效日期.10/20/1999也可以是一个有效的日期,但是10_/20_/1999将是一个非常奇怪的日期.
  7. 有些情况下没有分隔符.例如:10Jan1988.这些案例使用1中的单词.
  8. 根据闰年,有特殊情况,如2月28日或29日.此外,30或31天的月份.

我认为这些对于"天真"的分类来说已经足够了,语言专家可能会帮助你更多.

现在,您的算法的想法.速度无关紧要.同一个字符串可能有多个传递.优化何时开始重要.如果您怀疑自己找到了日期字符串,请将其存储在"安全"的某个地方ListOfPossibleDates并再次进行检查,使用从1到8的组合使用更严格的规则.当您认为日期字符串有效时,请将其提供给该Date课程,以确定它是否真的有效.1999年3月32日无效,当您将其转换为Date可理解的格式时.

一个重要的反复出现的模式是lookbehind和lookaround.当您认为找到有效的实体(日,月,年)时,您将不得不看到背后的内容.基于堆栈的机制或递归可能对此有所帮助.

脚步:

  1. 在字符串中搜索规则1中的单词.如果找到其中任何一个,请记下该位置.请注意月份.现在,在后面跟几个角色和几个角色看看等待你的是什么.如果您的月份之前和之后没有空格,并且有规则7中的数字,请检查它们的有效性.如果其中一个代表一天(必须是0-31)和其他一年(必须是0-9999,可能是AD或BC),则您有一个候选人.如果之前和之后有相同的分隔符,请查找6中的规则.始终记住,您必须确保存在有效组合.所以,32Jan1999不会这样做.
  2. 从规则2和3中搜索您的字符串中的其他英语单词.重复类似于步骤1.
  3. 搜索分隔符.空的空间将是最棘手的.尝试成对找到它们.所以,如果你的字符串中有一个"/",找到另一个,看看它们之间有什么.如果你发现了分离器的组合,那就是同样的事情.另外,使用步骤2中的算法.
  4. 搜索数字.有效值为0-9999,允许前导零.如果找到一个,请查找步骤3中的分隔符.

由于确实有无数的可能性,你将无法捕捉到它们.一旦找到了您认为可能再次发生的模式,将其存储在某处,您可以将其用作传递其他字符串的正则表达式.

我们举个例子吧"bla bla bla bla 12 Jan 09 bla bla bla 01/04/10 bla bla bla".提取第一个日期后12 Jan 09,然后使用该字符串的其余部分("bla bla bla 01/04/10 bla bla bla")并再次应用上述所有步骤.这样你就可以确定你没有错过任何东西.

我希望这些建议至少可以提供一些帮助.如果没有一个库可以为你做所有这些肮脏(和更多)的步骤,那么你就有了艰难的道路.祝好运!