Java日期时间API系列40-----中文语句中的时间语义识别(time NLP)代码实现分析
从上篇 Java日期时间API系列39-----中文语句中的时间语义识别(time NLP 输入一句话,能识别出话里的时间)原理分析 中得知解析的主要步骤分为三步:
(1)加载正则文件
(2)解析中文语句中的所有时间词语
(3)根据基准时间,循环解析(2)中的时间词语。
下面结合代码分析一下。
1.加载正则文件
(1)正则文件介绍:
TimeRegex.Gzip(原项目中名称为TimeExp.m)是所有解析识别的基础。解压后查看可以看到文件内部为大量正则表达式,如部分截图如下:

(2)单例加载
public class TextAnalysis {
private static volatile TextAnalysis instance;
private static Pattern pattern;
private boolean isPreferFuture;
private TextAnalysis(){
try {
pattern = RegexResourceUtil.readModel("TimeRegex.Gzip");
isPreferFuture = true;
} catch (Exception e) {
e.printStackTrace();
}
}
public static TextAnalysis getInstance(){
if(instance == null){
synchronized(TextAnalysis.class){
if(instance == null){
instance = new TextAnalysis();
}
}
}
return instance;
}
}
//RegexResourceUtil.readModel(String)
/**
* 获取Pattern
* @param fileName 文件名称
* @return Pattern 正则对象
* @throws Exception 异常
*/
public static Pattern readModel(String fileName) throws Exception {
try(InputStream resourceAsStream = RegexResourceUtil.class.getClassLoader().getResourceAsStream(fileName)){
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(new GZIPInputStream((resourceAsStream))));
Pattern p = (Pattern) in.readObject();
return Pattern.compile(p.pattern());
}
}
2.解析中文语句中的所有时间词语
/**
* 根据正则集合识别出时间词语
* @param text 待处理文本
* @return 时间词语
*/
public List<String> analysis(String text){
Matcher match;
int startline = -1, endline = -1; List<String> tempResult = new ArrayList<>();
tempResult.add("");
int rpointer = 0;// 计数器,记录当前识别到哪一个字符串了 match = pattern.matcher(text);
boolean startmark = true;
while (match.find()) {
startline = match.start();
if (endline == startline) // 假如下一个识别到的时间字段和上一个是相连的 @author kexm
{
rpointer--;
tempResult.set(rpointer, tempResult.get(rpointer) + match.group());// 则把下一个识别到的时间字段加到上一个时间字段去
} else {
if (!startmark) {
rpointer--;
rpointer++;
}
startmark = false;
tempResult.set(rpointer, match.group());// 记录当前识别到的时间字段,并把startmark开关关闭。这个开关貌似没用?
}
endline = match.end();
rpointer++;
if((tempResult.size()-1)<rpointer){
tempResult.add("");
}
}
if (rpointer > 0) {
rpointer--;
rpointer++;
}
return tempResult;
}
3.根据基准时间,循环解析(2)中的时间词语。
/**
* 时间表达式单元构造方法
* 该方法作为时间表达式单元的入口,将时间表达式字符串传入
*
* @param timeExpression 时间表达式字符串
* @param textAnalysis 正则文件分析类
* @param timePoint 上下文时间
*/ public TimeNLP(String timeExpression, TextAnalysis textAnalysis, TimeContext timePoint) {
this.timeExpression = timeExpression;
this.textAnalysis = textAnalysis;
this.timeContextOrigin = timePoint;
timeNormalization();
} /**
* 时间表达式规范化的入口
* <p>
* 时间表达式识别后,通过此入口进入规范化阶段,
* 具体识别每个字段的值
*/
private void timeNormalization() {
//标准时间解析
LocalDateTime localDateTime = normStandardTime();
if(localDateTime == null){
normYear();
normMonth();
normDay();
normMonthFuzzyDay();/**add by kexm*/
normBaseRelated();
normBaseTimeRelated();
normCurRelated();
normHour();
normMinute();
normSecond();
normTotal();
modifyTimeBase();
localDateTime = LocalDateTime.of(1970, 1, 1, 0, 0);
}
String[] timeGrid = new String[6];
timeGrid = timeContextOrigin.getTimeBase().split("-"); int tunitpointer = 5;
while (tunitpointer >= 0 && timeContext.getTunit()[tunitpointer] < 0) {
tunitpointer--;
}
for (int i = 0; i < tunitpointer; i++) {
if (timeContext.getTunit()[i] < 0)
timeContext.getTunit()[i] = Integer.parseInt(timeGrid[i]);
}
String[] resultTmp = new String[6];
resultTmp[0] = String.valueOf(timeContext.getTunit()[0]);
if (timeContext.getTunit()[0] >= 10 && timeContext.getTunit()[0] < 100) {
resultTmp[0] = "19" + String.valueOf(timeContext.getTunit()[0]);
}
if (timeContext.getTunit()[0] > 0 && timeContext.getTunit()[0] < 10) {
resultTmp[0] = "200" + String.valueOf(timeContext.getTunit()[0]);
} for (int i = 1; i < 6; i++) {
resultTmp[i] = String.valueOf(timeContext.getTunit()[i]);
}
if (Integer.parseInt(resultTmp[0]) != -1) {
timeNorm += resultTmp[0] + "年";
localDateTime = localDateTime.withYear(Integer.valueOf(resultTmp[0]));
if (Integer.parseInt(resultTmp[1]) != -1) {
timeNorm += resultTmp[1] + "月";
localDateTime = localDateTime.withMonth(Integer.valueOf(resultTmp[1]));
if (Integer.parseInt(resultTmp[2]) != -1) {
timeNorm += resultTmp[2] + "日";
localDateTime = localDateTime.withDayOfMonth(Integer.valueOf(resultTmp[2]));
if (Integer.parseInt(resultTmp[3]) != -1) {
timeNorm += resultTmp[3] + "时";
localDateTime = localDateTime.withHour(Integer.valueOf(resultTmp[3]));
if (Integer.parseInt(resultTmp[4]) != -1) {
timeNorm += resultTmp[4] + "分";
localDateTime = localDateTime.withMinute(Integer.valueOf(resultTmp[4]));
if (Integer.parseInt(resultTmp[5]) != -1) {
timeNorm += resultTmp[5] + "秒";
localDateTime = localDateTime.withSecond(Integer.valueOf(resultTmp[5]));
}
}
}
}
}
}
timeContextOrigin.setTunit(timeContext.getTunit().clone());
timeContext.setTimeBase(timeContextOrigin.getTimeBase());
timeContext.setOldTimeBase(timeContextOrigin.getOldTimeBase());
time = DateTimeConverterUtil.toDate(localDateTime);
timeNormFormat = DateTimeFormatterUtil.format(localDateTime, DateTimeFormatterUtil.YYYY_MM_DD_HH_MM_SS_FMT);
} //下面只举例 年的识别 /**
* 年-规范化方法
* <p>
* 该方法识别时间表达式单元的年字段
*/
private void normYear() {
/**假如只有两位数来表示年份*/
Pattern pattern = RegexEnum.NormYearTwo.getPattern();
Matcher match = pattern.matcher(timeExpression);
if (match.find()) {
timeContext.getTunit()[0] = Integer.parseInt(match.group());
if (timeContext.getTunit()[0] >= 0 && timeContext.getTunit()[0] < 100) {
if (timeContext.getTunit()[0] < 30) /**30以下表示2000年以后的年份*/
timeContext.getTunit()[0] += 2000;
else/**否则表示1900年以后的年份*/
timeContext.getTunit()[0] += 1900;
} }
/**不仅局限于支持1XXX年和2XXX年的识别,可识别三位数和四位数表示的年份*/
pattern = RegexEnum.NormYearFour.getPattern();
match = pattern.matcher(timeExpression);
if (match.find())/**如果有3位数和4位数的年份,则覆盖原来2位数识别出的年份*/ {
timeContext.getTunit()[0] = Integer.parseInt(match.group());
}
}
timenlp相关代码仍有很多需要不断优化的地方,欢迎参与。
Java日期时间API系列40-----中文语句中的时间语义识别(time NLP)代码实现分析的更多相关文章
- Java日期时间API系列39-----中文语句中的时间语义识别(time NLP 输入一句话,能识别出话里的时间)原理分析
NLP (Natural Language Processing) 是人工智能(AI)的一个子领域.自然语言是人类智慧的结晶,自然语言处理是人工智能中最为困难的问题之一(来自百度百科). 其中中文更是 ...
- Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。
通过Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneI ...
- Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate
通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用ja ...
- Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
目录 0.前言 1.TemporalAccessor源码 2.Temporal源码 3.TemporalAdjuster源码 4.ChronoLocalDate源码 5.LocalDate源码 6.总 ...
- Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全
通过Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter, 可以看出java8的DateTimeFormatter完美解决 ...
- Java日期时间API系列1-----Jdk7及以前的日期时间类
先看一个简单的图: 主要的类有: Date类负责时间的表示,在计算机中,时间的表示是一个较大的概念,现有的系统基本都是利用从1970.1.1 00:00:00 到当前时间的毫秒数进行计时,这个时间称为 ...
- java 日期和字符串互转,依据当天整天时间 得到当天最后一秒的日期时间
java 日期和字符串互转.依据当天整天时间 得到当天最后一秒的日期时间 package com.hi; import java.text.DateFormat; import java.text ...
- NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用
NET MVC全局异常处理(一) 目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...
- Java日期时间API系列13-----Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date等
从前面的系列博客中可以看出Jdk8中java.time包中的新的日期时间API类设计的很好,但Date由于使用仍非常广泛,这就涉及到Date转LocalDateTime,LocalDateTime转D ...
- Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类
因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...
随机推荐
- FP分数规划在无线通信中的应用
更多精彩内容请关注微信公众号 '优化与算法' 前言 在数学优化中,分数规划是线性分式规划的推广.分数规划中的目标函数是两个函数的比值,这两个函数通常是非线性的.要优化的比值通常描述系统的某种效率. 1 ...
- 【SpringBoot】01 快速上手
环境搭建: JDK8 + IDEA 2018 + SpringBoot + Maven 3.0 + 创建Boot项目 2020.6.1更新补充: 最近才发现SpringBoot用IDEA构建项目会发生 ...
- 【SpringMVC】11 拦截器
拦截器是AOP具体的应用 只能使用SpringMVC自己的组件有效 之拦截访问控制器方法的请求, 如果访问的是jsp.html.css.img.js这一类的静态资源,则不会拦截 演示: 编写一个拦截器 ...
- 【转载】pip install 使用多个.local环境
原文地址: https://zhuanlan.zhihu.com/p/351468170 ================================ 我们都知道anaconda可以安装不同的py ...
- MindSpore中使用model.train,在每一步训练结束后自动进行调用自定义函数 —— from mindspore.train.callback import Callback
在MindSpore中使用model.train训练网络时我们难以处理间断性的任务,为此我们可以考虑使用MindSpore中的Callback机制.Callback 函数可以在 model.train ...
- mujoco_py 运行example报错:ERROR: GLEW initalization error: Missing GL version ——— 解决方法
mujoco的安装与mujoco_py的安装参见: https://www.cnblogs.com/devilmaycry812839668/p/16004320.html mujoco_py安装成功 ...
- 构建无服务器数仓(二)Apache DolphinScheduler 集成以及 LOB 粒度资源消费分析
引言 在数据驱动的世界中,企业正在寻求可靠且高性能的解决方案来管理其不断增长的数据需求.本系列博客从一个重视数据安全和合规性的 B2C 金融科技客户的角度来讨论云上云下混合部署的情况下如何利用亚马逊云 ...
- 【安装部署】Apache SeaTunnel 和 Web快速安装详解
版本说明 由于作者目前接触当前最新版本为2.3.4 但是官方提供的web版本未1.0.0,不兼容2.3.4,因此这里仍然使用2.3.3版本. 可以自定义兼容处理,官方提供了文档:https://mp. ...
- 使用 Apache SeaTunnel 实现 Kafka Source 解析复杂Json 案例
版本说明: SeaTunnel:apache-seatunnel-2.3.2-SNAPHOT 引擎说明: Flink:1.16.2 Zeta:官方自带 前言 近些时间,我们正好接手一个数据集成项目,数 ...
- 20-canvas之形变
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...