NLP (Natural Language Processing) 是人工智能(AI)的一个子领域。自然语言是人类智慧的结晶,自然语言处理是人工智能中最为困难的问题之一(来自百度百科)。

其中中文更是不好处理。下面将分析中文语句中的时间的识别:time NLP 输入一句话,能识别出话里的时间。下面2种简单的实现方法。

 

1.单词的识别

这种比较简单,比如,今天,明天,下周,下月,明年,昨天,上周,上月,去年等。原理:匹配到明天就根据今天的时间天数加1。
  

/**
* 常用时间枚举
*
* @author xkzhangsan
*/
public enum CommonTimeEnum { TODAY("today", "今天"), TOMORROW("tomorrow", "明天"),
NEXTWEEK("nextWeek", "下周"),
NEXTMONTH("nextMonth", "下月"),
NEXTYEAR("nextYear", "明年"), YESTERDAY("yesterday", "昨天"),
LASTWEEK("lastWeek", "上周"),
LASTMONTH("lastMonth", "上月"),
LASTYEAR("lastYear", "去年"),
; private String code; private String name; public String getCode() {
return code;
} public String getName() {
return name;
} CommonTimeEnum(String code, String name) {
this.code = code;
this.name = name;
} public static Map<String, String> convertToMap(){
Map<String, String> commonTimeMap = new HashMap<String, String>();
for (CommonTimeEnum commonTimeEnum : CommonTimeEnum.values()) {
commonTimeMap.put(commonTimeEnum.getCode(), commonTimeEnum.getCode());
commonTimeMap.put(commonTimeEnum.getName(), commonTimeEnum.getCode());
}
return commonTimeMap;
} public static CommonTimeEnum getCommonTimeEnumByCode(String code){
for (CommonTimeEnum commonTimeEnum : CommonTimeEnum.values()) {
if(commonTimeEnum.getCode().equals(code)){
return commonTimeEnum;
}
}
return null;
}
} /**
* 解析自然语言时间,今天,明天,下周,下月,明年,昨天,上周,上月,去年等。
* @param text 自然语言时间,待解析字符串
* @param naturalLanguageMap 自定义自然语言时间map,其中key自定义,value需为 com.xkzhangsan.time.enums.CommonTimeEnum中的code;
* 可以为空,默认使用com.xkzhangsan.time.enums.CommonTimeEnum解析。
* @return Date
*/
public static Date parseNaturalLanguageToDate(String text, Map<String, String> naturalLanguageMap){
if(StringUtil.isEmpty(text)){
return null;
}
text = text.trim(); boolean isCommonTimeMap = false;
if(CollectionUtil.isEmpty(naturalLanguageMap)){
naturalLanguageMap = CommonTimeEnum.convertToMap();
isCommonTimeMap = true;
}
if(! naturalLanguageMap.containsKey(text) || StringUtil.isEmpty(naturalLanguageMap.get(text))){
return null;
} String targetMethod = null;
if(isCommonTimeMap){
targetMethod = naturalLanguageMap.get(text);
}else{
String code = naturalLanguageMap.get(text);
Map<String, String> commonTimeMap = CommonTimeEnum.convertToMap();
if(commonTimeMap.containsKey(code)){
targetMethod = commonTimeMap.get(code);
}
}
if(targetMethod == null){
return null;
} //执行结果
CommonTimeEnum targetCommonTime = CommonTimeEnum.getCommonTimeEnumByCode(targetMethod);
if(targetCommonTime == null){
return null;
} switch (targetCommonTime){
case TODAY :
return DateTimeCalculatorUtil.today();
case TOMORROW:
return DateTimeCalculatorUtil.tomorrow();
case NEXTWEEK:
return DateTimeCalculatorUtil.nextWeek();
case NEXTMONTH:
return DateTimeCalculatorUtil.nextMonth();
case NEXTYEAR:
return DateTimeCalculatorUtil.nextYear();
case YESTERDAY:
return DateTimeCalculatorUtil.yesterday();
case LASTWEEK:
return DateTimeCalculatorUtil.lastWeek();
case LASTMONTH:
return DateTimeCalculatorUtil.lastMonth();
case LASTYEAR:
return DateTimeCalculatorUtil.lastYear();
default:
return null;
}
} /**
* 明天
* @return Date
*/
public static Date tomorrow(){
return plusDays(today(), 1);
} /**
* 今天
* @return Date
*/
public static Date today(){
return new Date();
}

2.中文语句中的时间的识别

这个是真实语境下的时间识别,比如 Hi,all.下周一下午三点开会,如果今天是2021-06-10 那么 返回结果为:2021-06-14 15:00:00 。

2.1 原理和图解

原理和第一种类似,也是识别时间词语,根据基准时间推断结果,但更强大一些。

基本分为三步:

(1)加载正则文件

(2)解析中文语句中的所有时间词语

(3)根据基准时间,循环解析(2)中的时间词语

详细步骤如图:

                                                              

2.2 相关源码及说明

2.2.1 Time-NLP

github: https://github.com/shinyke/Time-NLP

author:shinyke

由复旦NLP中的时间分析功能修改而来,做了很多细节和功能的优化。

  1. 泛指时间的支持,如:早上、晚上、中午、傍晚等。
  2. 时间未来倾向。 如:在周五输入“周一早上开会”,则识别到下周一早上的时间;在下午17点输入:“9点送牛奶给隔壁的汉子”则识别到第二天上午9点。
  3. 多个时间的识别,及多个时间之间上下文关系处理。如:"下月1号下午3点至5点到图书馆还书",识别到开始时间为下月1号下午三点。同时,结束时间也继承上文时间,识别到下月1号下午5点。
  4. 可自定义基准时间:指定基准时间为“2016-05-20-09-00-00-00”,则一切分析以此时间为基准。
  5. 修复了各种各样的BUG。

简而言之,这是一个输入一句话,能识别出话里的时间的工具。

2.2.2 xk-time TimeNLPUtil

https://github.com/xkzhangsan/xk-time TimeNLPUtil

在Time-NLP基础上做了很多优化:

(1)封装属性,重命名使符合驼峰命名标准。
(2)将加载正则资源文件改为单例加载。
(3)将类按照功能重新划分为单独的多个类。
(4)使用Java8日期API重写。
(5)增加注释说明,优化代码。
(6)修复原项目中的issue:标准时间yyyy-MM-dd、yyyy-MM-dd HH:mm:ss和yyyy-MM-dd HH:mm解析问题。
(7)修复原项目中的issue:1小时后,1个半小时后,1小时50分钟等解析问题;并且支持到秒,比如50秒后,10分钟30秒后等。
(8)修复原项目中的issue:修复当前时间是上午10点,那么下午三点 会识别为明天下午三点问题。
(9)修复原项目中的issue:修复小数解析异常问题。
(10)性能优化,将使用到的正则预编译后放到缓存中,下次直接使用,提高性能。

3 实现方法的局限性

第一种只能识别单词;

第二种也只能识别正则文件中的词语,比第一种识别能力更强,但如果有新的或不常用的时间词语无法处理,比如星期一的同义词礼拜一等,如果要不断支持新的词语,需要不断的修改,不如机器学习好;

对于常用的时间词语识别,第二种已经达到很高的识别率。

4.开发这个功能的原因

第一种实现,因为有网友需要识别中文时间词语,我写了第一种的实现;

第二种实现,另一个网友有需要识别语句中的中文时间词语,他向往推荐了Time-NLP这个项目,说这个项目很好,不维护了,有一些小问题,希望我能参考实现,我研究了原项目代码,在我的项目中重写,优化,并修复了一些问题。

感谢shinyke,这个项目很好,学习到很多正则解析的知识。

源码地址: https://github.com/xkzhangsan/xk-time

Java日期时间API系列39-----中文语句中的时间语义识别(time NLP 输入一句话,能识别出话里的时间)原理分析的更多相关文章

  1. Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。

    通过Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneI ...

  2. Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate

    通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用ja ...

  3. Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

    目录 0.前言 1.TemporalAccessor源码 2.Temporal源码 3.TemporalAdjuster源码 4.ChronoLocalDate源码 5.LocalDate源码 6.总 ...

  4. Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全

    通过Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter, 可以看出java8的DateTimeFormatter完美解决 ...

  5. Java日期时间API系列13-----Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date等

    从前面的系列博客中可以看出Jdk8中java.time包中的新的日期时间API类设计的很好,但Date由于使用仍非常广泛,这就涉及到Date转LocalDateTime,LocalDateTime转D ...

  6. Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  7. Java日期时间API系列2-----Jdk7及以前的日期时间类在mysql数据库中的应用

    1.java中与数据库相关的时间类 java提供与mysql方便交互的三种数据类型: java.sql.Date java.sql.Time java.sql.Timestamp 它们都是继承java ...

  8. Java日期时间API系列1-----Jdk7及以前的日期时间类

    先看一个简单的图: 主要的类有: Date类负责时间的表示,在计算机中,时间的表示是一个较大的概念,现有的系统基本都是利用从1970.1.1 00:00:00 到当前时间的毫秒数进行计时,这个时间称为 ...

  9. Java日期时间API系列3-----Jdk7及以前的日期时间类的不方便使用问题

    使用Java日期时间类,每个人都很熟悉每个项目中必不可少的工具类就是dateutil,包含各种日期计算,格式化等处理,而且常常会遇到找不到可用的处理方法,需要自己新增方法,处理过程很复杂. 1.Dat ...

  10. Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的特点

    1.不变性 新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处. 比如:LocalDateTime 2.关注点分离 新的API将人可读的日期时间和机器时间(unix timestamp ...

随机推荐

  1. VS2010 支持 CSS3

    在安装Standards Update for VS2010 SP1后,VS2010中没有CSS3.0问题,以下是我的解决方法 1.首先去官网下载 CSS 3 Intellisense Schema ...

  2. Linux(Debian) vps安装gnome桌面+VNC

      昨天转载了一篇关于在Linux VPS上安装xface桌面并VNC连接的文章,因为文章是基于CentOS系统来操作的,有热心读者希望有一个Debian下的类似的东西,这就促成了今天的这篇文字.需要 ...

  3. iOS页面间传值的六种方式

    一般ios页面间的传值方式分为6种:1.属性传值:2.block:3.delegate:4.UserDefault:5.单例:6.通知. 0&1.block 先说我最常用的block吧,属性传 ...

  4. shell /bin/bash^M: bad interpreter错误解决

      错误原因之一很有可能是你的脚本文件是DOS格式的, 即每一行的行尾以\r\n来标识, 其ASCII码分别是0x0D, 0x0A.可以有很多种办法看这个文件是DOS格式的还是UNIX格式的, 还是M ...

  5. awk使用总结

    转载自董的博客 1. 什么是awk awk是Unix/Linux提供的样式扫描与处理工具,非常擅长处理结构化数据和生成表单.与sed 和grep 很相似,但功能却超过大于两者,由于awk具备各种脚本语 ...

  6. Python startswith() 函数 判断字符串开头

    Python startswith() 函数 判断字符串开头 函数:startswith() 作用:判断字符串是否以指定字符或子字符串开头 一.函数说明语法:string.startswith(str ...

  7. 深入理解JVM一垃圾回收器

    上一篇我们介绍了常见的垃圾回收算法,不同的算法各有各的优缺点,在JVM中并不是单纯的使用某一种算法进行垃圾回收,而是将不同的垃圾回收算法包装在不同的垃圾回收器当中,用户可以根据自身的需求,使用不同的垃 ...

  8. 最直白、最易懂的话带你认识和学会---数据分析基础包之numpy的使用

    前言 numpy是一个很基础很底层的模块,其重要性不言而喻,可以说对于新手来说是最基础的入门必须要学习的其中之一.在很多数据分析,深度学习,机器学习亦或是人工智能领域的模块中,很多的底层都会用到这个模 ...

  9. hadoop修改

    https://github.com/medcl/elasticsearch-analysis-ik/releases hadoop-/etc/hadoop/core-site.xml <con ...

  10. Returning Values from Bash Functions

    转自:https://www.linuxjournal.com/content/return-values-bash-functions Bash functions, unlike function ...