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提交了 ...
随机推荐
- python_xecel
移动并重命名工作簿 1 from pathlib import Path # 导入pathlib模块的path类 2 import time 3 4 # Press the green button ...
- Fidder响应数据SyntaxView乱码的处理方法
当Fidder查看响应数据"SyntaxView"出现乱码时,可以点击上方菜单栏的"Decode"按钮,等"Decode"出现蓝色边框后再重 ...
- 【SpringCloud】 Re01
简单理解 接口跨服务调用 说白了 就是原来只是调用一个接口就能得到资源,现在是调用两个或者更多接口,这些接口来自不同的服务 (从前端的角度来看依然只是调用这个接口,只是这个接口背后又去调用其他的接口了 ...
- 【Layui】04 导航 Nav
文档地址: https://www.layui.com/doc/element/nav.html 演示案例: <ul class="layui-nav" lay-filter ...
- Http、Https简介和Session、token的请求流程
Http Http (超文本输出协议) 是一种分布式.协作式和超媒体信息系统的应用层协议,它通常运行在TCP之上,因特网应用最广泛的便是Http协议,所有www都遵循这个标准.主要用于Web 浏览器与 ...
- 人形机器人(humanoid)(双足机器人、四足机器人)—— 操控员 —— 机器人数据收集操作员
参考: https://www.youtube.com/watch?v=jbQ4M4SNb2M 机器人数据收集操控员,就和大模型训练数据收集员.数据类型标识员(打标签人员)一样,都是为了人工生成AI训 ...
- 强化学习中的“sample efficiency”应该如何翻译 —— “样本效率”还是“采样效率”
问题: 强化学习中的"sample efficiency"应该如何翻译 -- "样本效率"还是"采样效率" 答案: 具体看上下文内容.如果是 ...
- 使用 Apache DolphinScheduler 进行 EMR 任务调度
By AWS Team 前言 随着企业规模的扩大,业务数据的激增,我们会使用 Hadoop/Spark 框架来处理大量数据的 ETL/聚合分析作业,⽽这些作业将需要由统一的作业调度平台去定时调度. 在 ...
- WPF,图表控件
开源代码地址:https://github.com/bearhanQ/WPFFramework; QQ群:332035933: <UserControl x:Class="WpfBoo ...
- 面试必问之kafka
问题1:消息队列的作用 1. 解耦 快递小哥手上有很多快递需要送,他每次都需要先电话一一确认收货人是否有空.哪个时间段有空,然后再确定好送货的方案.这样完全依赖收货人了!如果快递一多,快递小哥估计的忙 ...