如何在Java中从字符串中识别日期

20

最近我遇到了一个相当“简单”的问题。假设有一些句子(保存在一个字符串中),我需要找出其中是否有任何日期。挑战在于日期可以以许多不同的格式出现,以下是一些示例:

  • 1956年6月12日
  • 2014年10月21日伦敦
  • 1999年10月13日
  • 2003年1月11日

值得一提的是这些都包含在一个字符串中。例如:

String s = "This event took place on 13 October 1999.";
在这种情况下,我的问题是如何检测出字符串中是否有日期。我最初的想法是搜索单词"event",然后尝试定位日期。但由于日期格式越来越多,这种解决方案并不美观。我尝试的第二种方法是创建一个月份列表并进行搜索。这样效果不错,但仍会漏掉日期全部使用数字表示的情况。
到目前为止,我尚未尝试过的一种解决方案是设计正则表达式并在字符串中查找匹配项。不确定这种解决方案可能降低多少性能。
有没有好的解决方案值得我考虑?有没有人遇到过类似的问题,你们找到了什么解决方案?
有一件事情是肯定的,那就是没有时间,因此唯一有趣的部分就是日期。

我能想到的接近这个问题的唯一方法就是结合你所有的方法。例如,在字符串中查找月份,然后尝试查找美国日期(MM/DD/YYYY),再尝试查找欧洲日期(DD.MM.YYYY)...... 这取决于你收到的字符串的类型!如果某个字符串包含“它发生在1989年第一个月的第一天”,你可能无法实现它! - ParkerHalo
唯一的方法是解析您的字符串。 - Nvan
3
我记得有一个遇到同样问题的人:https://dev59.com/NpDea4cB1Zd3GeqPWAmg#33099268 - Emanuele Ivaldi
2
这不是一个简单的问题。如果你需要确定日期,那么它是无解的:你最后的例子可能是11月1日或1月11日。 - edc65
4个回答

23
使用natty.joestelmach.com
Natty是一个用Java编写的自然语言日期解析器。给定一个日期表达式,natty将应用标准语言识别和翻译技术,以产生一组相应的日期,其中包括可选的解析和语法信息。
import com.joestelmach.natty.*;

List<Date> dates =new Parser().parse("Start date 11/30/2013 , end date Friday, Sept. 7, 2013").get(0).getDates();
        System.out.println(dates.get(0));
        System.out.println(dates.get(1));

//output:
//Sat Nov 30 11:14:30 BDT 2013
//Sat Sep 07 11:14:30 BDT 2013

1
在我尝试过的事情中,这个结果最好。 - bbakiu
我认为GATEANNIE做得更好。 - Identity1

3

1
如果只有一个字符串,您可以像您提到的那样使用正则表达式。需要找到不同的日期格式表达式。以下是一些示例: 正则表达式 - 日期 如果是文档或大文本,则需要解析器。您可以使用词法分析方法。 词法分析 根据项目的不同,使用外部库可能是个好主意。有时这不是一个选项。

1
正则表达式对于这个会很困难。 - Identity1

0

我以前做过这个,具有良好的精度召回率。您需要使用GATE及其ANNIE插件。

  1. 使用GATE UI工具创建一个包含您的处理资源.GAPP文件。

  2. 使用.GAPP文件来使用提取的日期注释集。

步骤2可以按以下方式完成:

Corpus corpus = Factory.newCorpus("Gate Corpus");
Document gateDoc = Factory.newDocument("This event took place on 13 October 1999.");
corpus.add(gateDoc);
File pluginsHome = Gate.getPluginsHome();
File ANNIEPlugin = new File(pluginsHome, "ANNIE");
File AnnieGapp = new File(ANNIEPlugin, "Test.gapp");
AnnieController =(CorpusController) PersistenceManager.loadObjectFromFile(AnnieGapp);
AnnieController.setCorpus(corpus);
AnnieController.execute();

稍后您可以像这样查看提取的注释:

AnnotationSetImpl ann = (AnnotationSetImpl) gateDoc.getAnnotations();
System.out.println("Found annotations of the following types: "+ gateDoc.getAnnotations().getAllTypes());

我相信你可以很容易地使用内置的注释集Date来完成它。它也非常可扩展。

要增强注释集Date,可以在JAPE中创建一个宽松的注释规则,称为“DateEnhanced”,从内置的ANNIE注释Date中包括某些类型的日期,如“9/11”,并在“DateEnhanced”注释JAPE RULE的Java正则表达式链接上使用链式过滤一些不需要的输出(如果有的话)。


如果文本不是英语而是法语,这个解决方案是否有效? - bbakiu
@bbakiu https://gate.ac.uk/gate/doc/plugins.html#Lang_French。至于日期,我会说是的。 - Identity1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接