`
kanpiaoxue
  • 浏览: 1781367 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

java语言时间表达式引擎(2)

 
阅读更多

 

在原有《java语言时间表达式引擎》https://www.iteye.com/blog/kanpiaoxue-2217121 的基础上进行了精简。

时间表达式也进行了微调,改为: {dt:格式化字符串,offset}

 

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;

import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 时间表达式引擎
 *
 * @ClassName: DateExpressionEngine
 * @author kanpiaoxue
 * @version 1.0
 * @CreateTime: 2020/06/29 20:28:06
 * @Description:
 */
public class DateExpressionEngine {

    private static final Pattern PATTERN = Pattern.compile("(\\{dt:(.*?)\\})");
    private static final Pattern OFFSET_PATTERN = Pattern.compile("^(-?\\d+?)?([y,Y,M,w,W,d,D,H,h,m])$");
    private static final Pattern OFFSET_SPECIAL_PATTERN = Pattern.compile("^([F,f,E,e])([M,w,W,q,Q])$");

    private static final String FIRST_STRING = "F";
    private static final String END_STRING = "E";
    private static final String YEAR_STRING = "y";
    private static final String QUARTR_STRING = "Q";
    private static final String MONTH_STRING = "M";
    private static final String WEEK_STRING = "w";
    private static final String DAY_STRING = "d";
    private static final String HOUR_STRING = "H";
    private static final String MINUTE_STRING = "m";
    private static final int PAIR_LENGTH = 2;
    private static final int ZERO = 0;

    /**
     *
     * @param text
     *            需要处理的字符串
     *
     *            <pre>
     *  里面可以含有任意多个时间表达式
     *  格式:dateFormat[,offset]}
     *  dateFormat: 符合java的java.text.DateFormat规范的表达式
     *  DateUnit 时间格式单位:[注意大小写]
     *      y   :   year
     *      M   :   Month
     *      d   :   day
     *      w   :   week
     *      H   :   Hour
     *      m   :   minute
     *
     *  [重点]这里的格式有两种,一种是一般日期表达式,一种是特殊表达式
     *
     *  一、一般日期表达式:
     *  offset的表达式:(-)?number+DateUnit
     *  offset的正则表达式: ^((?:-)?\\d+?)([y,M,w,d,H,m])$
     *
     *   example:
     *      {dt:MM} {dt:MMdd} {dt:MM/dd} {dt:HH} {dt:HHmm}
     *      {dt:yyyyMMdd} {dt:yyyy-MM-dd} {dt:yyyy/MM/dd}
     *      {dt:yyyyMMddHH} {dt:yyyy-MM-dd HH} {dt:yyyy/MM/dd HH}
     *      {dt:yyyyMMddHHmm} {dt:yyyy-MM-dd HH:mm} {dt:yyyy/MM/dd HH:mm}
     *      {dt:yyyyMMdd,-1y} {dt:yyyy-MM-dd,-1y} {dt:yyyy/MM/dd,-1y}
     *      {dt:yyyyMMdd,-1M} {dt:yyyy-MM-dd,-1M} {dt:yyyy/MM/dd,-1M}
     *      {dt:yyyyMMdd,1d} {dt:yyyy-MM-dd,1d} {dt:yyyy/MM/dd,1d}
     *      {dt:yyyyMMddHH,1H} {dt:yyyy-MM-dd HH,1H} {dt:yyyy/MM/dd HH,1H}
     *      {dt:yyyyMMdd,1w} {dt:yyyy-MM-dd,1w} {dt:yyyy/MM/dd,1w}
     *      {dt:yyyyMMddHHmm,10m} {dt:yyyy-MM-dd HH:mm,10m} {dt:yyyy/MM/dd HH:mm,10m}
     *
     * 二、特殊表达式
     *  用来计算:季度初/末,月初/末,周初/末(也就是周一和周日)
     *  offset的表达式:position+DateUnit
     *  offset的正则表达式:^([F,f,E,e])([M,w,W,q,Q])$
     *  ------------------
     *  F,f means: first
     *  E,e means: end
     *  ------------------
     *  M : Month
     *  w,W : Week
     *  q,Q : Quarter
     *
     *            </pre>
     *
     * @param dateTime
     *            时间
     * @return 经过计算之后的字符串
     */
    public static String formatDateExpression(String text, DateTime dateTime) {
        Preconditions.checkArgument(StringUtils.isNotBlank(text), "text is null or empty!");
        Preconditions.checkNotNull(dateTime, "dateTime is null");
        Matcher m = PATTERN.matcher(text);
        Map<String, String> map = Maps.newHashMap();

        /**
         * 如果找到时间表达式则进行替换,如果找不到,则不进行处理
         */
        while (m.find()) {
            /**
             * <pre>
             *
             * {dt:expression} is group(1) , as:  {dt:yyyyMMdd,-1y} , {dt:yyyyMMdd,FQ}
             * expression is group(2) , as: yyyyMMdd,-1y , yyyyMMdd,FQ
             * </pre>
             */
            String expression = m.group(2);
            // expressionWrapper : {dt:yyyyMMdd,-1y} , {dt:yyyyMMdd,FQ}
            String expressionWrapper = text.substring(m.start(1), m.end(1));
            // 格式化时间
            String replaceString = formatDateTime(expression, dateTime);
            map.put(expressionWrapper, replaceString);
        }
        // 替换表达式为正确的时间字符串
        for (Entry<String, String> kv : map.entrySet()) {
            text = StringUtils.replace(text, kv.getKey(), kv.getValue());
        }
        return text;
    }

    private static String formatDateTime(String express, DateTime dateTime) {
        // 将表达式切分开
        List<String> lst = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(express);
        int size = lst.size();
        Preconditions.checkArgument(size <= PAIR_LENGTH, unexpected(express));
        // 如果存在复杂的计算表达式
        if (lst.size() == PAIR_LENGTH) {
            String offsetExpression = lst.get(1);
            // 处理季度、月、周的第一天和最后一天
            Matcher m = OFFSET_SPECIAL_PATTERN.matcher(offsetExpression);
            if (m.matches()) {
                dateTime = processFirstOrLast(express, dateTime, m);
            } else {
                // 处理一般的时间表达式
                dateTime = processNormal(express, dateTime, offsetExpression);
            }
        }
        // 得到时间表达式的格式化部分
        String format = lst.get(0);
        return dateTime.toString(format);
    }

    private static DateTime processFirstOrLast(String express, DateTime dateTime, Matcher sm) {
        String str = sm.group(1);
        Preconditions.checkArgument(StringUtils.isNotBlank(str), unexpected(express));
        String unit = sm.group(2);
        if (QUARTR_STRING.equalsIgnoreCase(unit)) {
            dateTime = processQuarter(express, dateTime, str);
        } else if (MONTH_STRING.equals(unit)) {
            dateTime = processMonth(express, dateTime, str);
        } else if (WEEK_STRING.equalsIgnoreCase(unit)) {
            dateTime = processWeek(express, dateTime, str);
        }
        return dateTime;
    }

    private static DateTime processMonth(String express, DateTime dateTime, String str1) {
        if (FIRST_STRING.equalsIgnoreCase(str1)) {
            dateTime = dateTime.dayOfMonth().withMinimumValue();
        } else if (END_STRING.equalsIgnoreCase(str1)) {
            dateTime = dateTime.dayOfMonth().withMaximumValue();
        } else {
            throw new IllegalArgumentException(unexpected(express));
        }
        return dateTime;
    }

    private static DateTime processNormal(String express, DateTime dateTime, String offsetExpression) {
        Matcher m = OFFSET_PATTERN.matcher(offsetExpression);
        Preconditions.checkArgument(m.matches(), unexpected(express));
        String numString = m.group(1);
        int num = StringUtils.isBlank(numString) ? ZERO : Integer.valueOf(numString).intValue();
        if (ZERO == num) {
            // 如果是 offset == 0, 不需要进行下面的单位转换,直接返回当前时间
            return dateTime;
        }

        String unit = m.group(2);
        if (YEAR_STRING.equalsIgnoreCase(unit)) {
            // IgnoreCase
            dateTime = dateTime.plusYears(num);
        } else if (MONTH_STRING.equals(unit)) {
            dateTime = dateTime.plusMonths(num);
        } else if (WEEK_STRING.equalsIgnoreCase(unit)) {
            // IgnoreCase
            dateTime = dateTime.plusWeeks(num);
        } else if (DAY_STRING.equalsIgnoreCase(unit)) {
            // IgnoreCase
            dateTime = dateTime.plusDays(num);
        } else if (HOUR_STRING.equalsIgnoreCase(unit)) {
            // IgnoreCase
            dateTime = dateTime.plusHours(num);
        } else if (MINUTE_STRING.equals(unit)) {
            dateTime = dateTime.plusMinutes(num);
        } else {
            throw new IllegalArgumentException(unexpected(express));
        }
        return dateTime;
    }

    private static DateTime processQuarter(String express, DateTime dateTime, String str) {
        DateTime startQuarter = dateTime.plusMonths(0 - (dateTime.monthOfYear().get() - 1) % 3).dayOfMonth()
                .withMinimumValue();
        if (FIRST_STRING.equalsIgnoreCase(str)) {
            // 季度初
            dateTime = startQuarter;
        } else if (END_STRING.equalsIgnoreCase(str)) {
            // 季度末
            dateTime = startQuarter.plusMonths(3).plusDays(-1);
        } else {
            throw new IllegalArgumentException(unexpected(express));
        }
        return dateTime;
    }

    private static DateTime processWeek(String express, DateTime dateTime, String str1) {
        if (FIRST_STRING.equalsIgnoreCase(str1)) {
            dateTime = dateTime.dayOfWeek().withMinimumValue();
        } else if (END_STRING.equalsIgnoreCase(str1)) {
            dateTime = dateTime.dayOfWeek().withMaximumValue();
        } else {
            throw new IllegalArgumentException(unexpected(express));
        }
        return dateTime;
    }

    private static String unexpected(String express) {
        return String.format("unexpected expression format:%s", express);
    }
}

 

分享到:
评论

相关推荐

    Fel Javael表达式引擎

    Fel Java表达式引擎是一款轻量级且高效的开源表达式计算引擎。它的全称是FastExpressionLanguage,专门设计用于满足不断变化的功能需求和性能需求。Fel的执行方式主要依赖于函数,运算符如加减乘除等被视为Fel函数,...

    高速 Fel表达式引擎

    ### 高速 Fel表达式引擎知识点详解 #### 一、Fel表达式引擎概述 Fel(Fast Expression Language)是一种高性能的表达式引擎,旨在满足企业级应用对于表达式处理的需求。它具备快速执行的能力,与ognl等其他流行...

    表达式引擎fel-0.9版本

    6. **API集成**:Fel-all-0.9.tar.gz文件包含了一个完整的Fel引擎包,很可能提供了方便的Java API,使得开发者能够轻松地将Fel引擎集成到Java项目中,进行表达式的创建、编译和执行。 7. **扩展性**:Fel引擎可能...

    java表达式引擎

    Java表达式引擎是指能够解析和计算表达式的软件组件,它能够从字符串形式的表达式中获取值、执行方法调用等操作。在Java领域中,表达式引擎常常用于处理动态计算需求,如模板引擎、规则引擎等场景。 从提供的文件...

    Java根据正则表达式生成字符串—Xeger,automaton

    在Java中,我们可以使用RE2J库,它是Google开发的一个高效、安全的正则表达式引擎,支持构造有限状态自动机。虽然RE2J主要设计用于正则表达式的匹配,但通过它的内部机制,我们可以间接地实现字符串生成。 下面是一...

    Fel表达式引擎

    Fel表达式引擎在Java应用中尤其常见,它能够嵌入到各种系统中,提升程序的可扩展性和灵活性。 **一、Fel语法基础** 1. **变量和常量**:Fel支持变量和常量的使用。变量以$开头,例如`$name`,常量则直接书写,如`...

    浅谈Java中正则表达式的优化方法

    尤其是在Java语言环境中,`java.util.regex`包提供了丰富的API来支持正则表达式的创建与使用。然而,在实际应用中,随着正则表达式的复杂度增加,其执行效率往往会成为性能瓶颈之一。本文将深入探讨Java中正则表达式...

    java解析表达式JEXL实现办法

    JEXL(Java Expression Language)是Apache Commons项目提供的一种轻量级的表达式语言,它允许我们在Java应用程序中方便地执行JavaScript风格的表达式。本文将深入探讨如何使用JEXL在Java中解析和执行表达式。 首先...

    java解释算术表达式

    在这个场景中,我们关注的是一个用Java编写的专门用于解析算术表达式的解释器。Java是一种广泛使用的面向对象的编程语言,以其跨平台性和强大的库支持而著名。下面我们将深入探讨Java解释算术表达式这一主题。 首先...

    java 计算数学表达式

    在Java编程语言中,计算数学表达式是一项常见的需求,它涉及到字符串解析、语法分析和运算符优先级处理等多个环节。`jeval-0.9.4`是一个Java库,专门用于解析和评估数学表达式。这个库使得开发人员能够轻松地在程序...

    JAVA 正则表达式(超详细)

    2. Java 正则表达式的历史:Java 一直以来没有自带对正则表达式的支持,直到 Java 1.40 版本引入了 java.util.regex 包。之前,许多第三方类库提供了对正则表达式的支持,但这些类库都不一致、兼容性差。 3. ...

    IK Expression(表达式引擎)

    IK Expression 是一个开源的(OpenSource),可扩展的(Extensible), 基于java 语言开发的一个超轻量级(Super lightweight)的公式化语言解析执行 工具包。它是一个采用逆波兰式算法结合指针栈优化的公式解析引擎...

    java正则表达式详解java正则表达式详解

    Java正则表达式是Java编程语言中用于处理字符串的强大工具,它允许程序员通过模式匹配来查找、替换或分割文本。正则表达式(Regular Expression,简称regex)是一种由字符、元字符和操作符组成的模式,可以用来匹配...

    一个简单java表达式解析的程序

    Java表达式解析是编程中的一个重要概念,特别是在设计编译器、解释器或脚本引擎时。这个程序可能是为了理解并执行简单的数学或逻辑表达式,比如`2 + 3 * (4 - 5)`。在Java中实现这样的解析器,我们需要理解表达式...

    java实现多种计算器功能包含表达式

    在Java编程语言中实现一个多功能计算器,涉及到许多关键知识点,包括但不限于基础的算术运算、字符串解析、表达式求值、异常处理以及用户界面设计。下面将详细阐述这些知识点。 1. **基础算术运算**:计算器的核心...

    java的BeanShell公式执行引擎

    Java的BeanShell是一个轻量级、动态的脚本语言,它是专门为Java平台设计的,允许在运行时执行Java代码或者类似JavaScript的语法。BeanShell在Java应用中常被用来进行快速原型开发、测试以及扩展,它提供了一种简单的...

    正则表达式的调试器java实现

    7. **使用NetBeans**:NetBeans是一个流行的开源IDE,支持多种编程语言,包括Java。在NetBeans中开发这个项目,开发者可以利用其内置的项目管理、代码编辑、调试和构建工具,使得开发流程更加高效和便捷。 在压缩包...

    IKExpressoin简易表达式引擎V2.1.0使用说明.rar_IKExpressoin_V2 _ik表达式

    IKExpression是一款针对Java平台的轻量级表达式引擎,主要用于解析和执行用户自定义的表达式,从而实现程序的动态配置和灵活性。IKExpression V2.1.0是该引擎的升级版本,提供了更高效、稳定和易用的特性。 在...

Global site tag (gtag.js) - Google Analytics