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

java表达式解析,附加源码

阅读更多

java表达式解析器:ExpressionAnalyzer

 

本表达式解析器使用java语言实现。

支持算术运算、逻辑运算、比较运算,

支持if分支结构的解析,

支持在表达式中使用自定义函数,

支持多种数据类型:数字、日期、字符、字符串、布尔。

 

首先简单介绍表达式解析器的词法规则

  • 数据类型

支持五种数据类型:数字、日期、布尔、字符、字符串

 

  • 数字

数字类型在解析过程中将被转化成BigDecimal类型,支持以下格式:

整数123

小数123.333

指数1.2E2 1.2e2(即120

 

  • 日期

支持两种形式的日期数据,一种是精确到日的,写法为[yyyy-MM-dd],如[2012-03-31];另一种精确到秒,写法为[yyyy-MM-dd HH:mm:ss],如[2012-03-31 09:06:10]

在表达式解析过程中日期类型将转化为java.util.Calendar

 

  • Boolean

布尔常量的写法可以是trueTRUEfalseFALSE

 

  • 字符

字符分普通字符和转义字符。

普通字符:’a’’_’

转义字符:’\n’’\r’

 

  • 字符串

字符串用双引号表示,可包含转义字符,如”Hello World””Hello \r\n World”

 

  • 变量

变量名以字母或下划线开头,只能包含字母、数字、下划线,如:abc_abc_a1

 

  • 操作符

算术操作符:+ - * / %(取余);

逻辑操作符:&&||!

比较操作符:> >= < <= == !=

赋值操作符:=

 

以下是表达式解析器的使用介绍

  • 创建表达式

Expression的实例表示一个表达式,可通过Expression的构造函数创建或者使用ExpressionFactory创建。

表达式由语句组成,每个语句必须由分号结尾。定义表达式时可包含一个语句或多个语句,解析结果是被执行的最后一个语句的结果。

Expression有三个构造函数,可分别接受参数StirngInputStreamReader。下面以String为例创建表达式。

1. 使用构造函数创建

Expression exp = new Expression("a=1;  a + a*100;");

2.  使用ExpressionFactory创建

ExpressionFactory factory = ExpressionFactory.getInstance();
Expression exp = factory.getExpression("a=1;  a + a*100");

 

  • 执行表达式

通过调用Expressionevaluate()方法执行表达式:ExpressionFactory factory = ExpressionFactory.getInstance();

Expression exp = factory.getExpression("a=1;b=a*100;");
Valuable result = exp.evaluate();

表达式的执行结果以接口Valuable表示,Valuable提供如下方法:

 

public DataType getDataType();
public int getIndex();
public BigDecimal getNumberValue();
public String getStringValue();
public Character getCharValue();
public Calendar getDateValue();
public Boolean getBooleanValue();
public Object getValue();

如果表达式的结果是数字,可以这样取值:

 

BigDecimal number = result.getNumberValue();

如果忽略执行结果的类型,可以通过getValue方法取得Object()的执行结果。通过getDataType方法可以获得执行结果的具体类型。

 

以下部分将详细介绍各种表达式的具体使用。

  • 算术表达式

算术表达式只支持数字类型的常量、变量或表达式,可使用括号运算符:

100 / (2 * 50);

100 / (50 + 50);

 

  • 字符串连接

字符串和字符可以使用 + 连接。

例如,"Hello" + "World" + '!';

 

  • 逻辑表达式

逻辑表达式只支持布尔类型的常量、变量或表达式,可使用括号运算符:

( 2>1  ||  false)   &&  (false  ||  1<2);

 

  • 比较运算

支持数字、字符、字符串、日期类型的比较,不支持布尔类型的比较。

"zxc" > "abc";

'b' >= 'a';

1+1 < 1;

[2012-03-31] > [2012-03-01];

 

  • 赋值语句

第一次给变量赋值时确定了变量的类型,后续语句中不能给变量赋以不同的类型,否则抛出ArgumentsMismatchException异常。

例执行语句 a = “Hello Word”;  a=1; 将会抛出异常:

Type mismatch in assignment: cannot convert from String to Number.

 

  • 函数

1.系统函数

表达式解析器目前只提供了三个系统函数:abs(取绝对值)、max(取最大值)和judge(判断)。

函数的调用支持嵌套:

 

Expression expression = factory.getExpression("1 + max(1,abs(-2)) + abs(-1);");

judge函数共接受三个参数,第一个参数为布尔类型,第二和第三个参数为任意类型,例如judge(2>1,  "2",  "1")将返回字符串”2”

 

函数参数可以是固定个数的参数,如judge,也可以是任意多个参数,如absmax。

 

2.自定义函数

 

通过继承抽象类Function可以自定义函数。

Function有两个构造函数Function(String) function(String, DataType[])Function(String)接受函数名,function(String, DataType[])接受函数名和参数类型数组。

继承Function还需要实现两个抽象方法:getArgumentNum()返回参数个数,execute(Valuable[])实现函数执行逻辑,并返回执行结果。

下面介绍如何自定义无参函数、固定参数函数和任意数量参数的函数。

 

(1)无参函数

定义无参函数时,getArgumentNum()返回0,且构造函数中无需传入参数类型数组。比如定义一个函数取得当前日期,函数名为getDate

 

import java.util.Calendar;
import java.util.Date;

import neu.sxc.expression.syntax.function.Function;
import neu.sxc.expression.tokens.Valuable;

public class CurrentDate extends Function {
	public CurrentDate() {
		super("getDate");
	}
	public int getArgumentNum() {
		return 0;
	}
	@Override
	protected Object executeFunction(Valuable[] arguments) {
		Calendar date = Calendar.getInstance();
		date.setTime(new Date());
		return date;
	}
}

 

(2)固定参数函数

以上面提到的judge函数为例:

 

import neu.sxc.expression.tokens.DataType;
import neu.sxc.expression.tokens.Valuable;

public class Judge extends Function {
	
	public Judge() {
		super("judge", new DataType[]{DataType.BOOLEAN, DataType.ANY, DataType.ANY});
	}

	public int getArgumentNum() {
		return 3;
	}

	@Override
	protected Object executeFunction(Valuable[] arguments) {
		boolean condition = arguments[0].getBooleanValue();
		if(condition)
			return arguments[1].getValue();
		else
			return arguments[2].getValue();
	}
}

 getArgumentNum()返回3,构造函数中DataType.ANY表示参数为任意类型

 

(3)任意数量参数的函数

     以上面提到的max函数为例:

 

import java.math.BigDecimal;

import neu.sxc.expression.tokens.DataType;
import neu.sxc.expression.tokens.Valuable;

public class Max extends Function {

	public Max() {
		super("max", new DataType[]{DataType.NUMBER});
	}

	public int getArgumentNum() {
		return -1;
	}

	@Override
	public Object executeFunction(Valuable[] arguments) {
		BigDecimal result;
		if(arguments.length == 0) {
			result = new BigDecimal("0");
		} else {
			result = arguments[0].getNumberValue();
			for(int i=1; i<arguments.length; i++)
				if(result.compareTo(arguments[i].getNumberValue()) < 0)
					result = arguments[i].getNumberValue();
		}
		return result;
	}
}

 getArgumentNum()返回-1,表示参数为任意个数。对于任意数量参数的函数,参数必须为同一类型,所以在构造函数中传入的参数类型数组为:new DataType[]{DataType.NUMBER}

 

3.定义函数注册

 

系统函数不需要注册,可以直接使用。使用自定义函数,必须先调用ExpressionaddFunction方法,将函数注册到表达式,才能使用。以上面的取当前日期函数为例,

 

Expression expression = factory.getExpression("getDate();");
expression.addFunction(new CurrentDate());
expression.evaluate();

 

  • if语句

If语句的使用形式为:

if(Boolean)                endif        

if(Boolean)                else           endif

对于在分支内部定义的变量,其作用域仅为所在分支,在后续语句中不能直接使用,否则抛出变量为定义异常。

If语句的执行结果是最后一个被有效执行的语句,如:

 

 

if(2>1)

         a=abs(-3);

         if(false)

                   a=a+1;

         else

                   a=a+2;

         endif

         a=a+1;

else

         if(2>1)

                   a=9;

         endif

endif

 

执行结果为6

  • 获得表达式中涉及的所有变量名

Expression提供函数getVariableNames(),以Set<String>返回表达式中的所有变量名。

  • 获取变量值

表达式执行完成后,可以通过getVariableValue(String)取得变量的值,传入参数为变量名;

还可以调用getVariableTable()取得所有变量的值,返回类型为Map<String, Valuable>,其中存储了变量名和变量值的键值对。

  • 设置变量值

表达式中某变量的初始值也可从外部设置,调用setVariableValue(String, Object);

 

 

Expression expression = factory.getExpression("a + 1;");

expression.setVariableValue("a", 1);

expression.evaluate();     //结果为2


 

 

 

 

 

 

分享到:
评论

相关推荐

    java表达式解析,附加

    这篇博客文章,虽然链接不可用,但我们可以基于常规的Java表达式解析知识进行深入探讨。 1. **Java表达式**: Java表达式是程序中的一部分,用于计算一个值。它可以是简单的变量引用、常量,也可以是复杂的运算组合...

    Fel Javael表达式引擎

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

    javaparser教程

    JavaParser是一个广泛使用的Java源码解析库,它能够对Java代码进行解析、转换和生成。这个库特别适用于需要对Java代码进行静态分析和转换的场景,如代码重构、代码生成或者代码质量分析等。JavaParser的功能十分强大...

    javabiginteger源码-bytes-java:Bytes是一个实用程序库,可以轻松地在Java中创建、解析、转换、验证和转换字节数组

    biginteger源码Java 字节实用程序库 Bytes 是一个实用程序库,可以轻松地在 Java 中创建、解析、转换、验证和转换字节数组。 它的主类Bytes是字节和主要 API 的集合。 它支持写时复制和可变访问,因此调用者可能会...

    正则表达式

    代括号的子表达式数多,那么它就会被解析为一个十进制的转义序列,而不是一个引用.你可以坚持使用完整的三个字符来表示转义序列,这们就可以避免混淆了.例如, 使用 \044,而不是\44.下面是正则表达式的选择、分组和...

    jdom源码+jdom.jar

    2. **`Attribute`**:表示XML元素的属性,用于存储元素的附加信息。 3. **`Document`**:表示整个XML文档,包括根元素、文档类型声明(如果存在)以及其他元数据。 4. **`Builder`**:用于从XML字符串或输入流构建...

    java毕设之javaWeb物资管理系统项目源码.rar

    【标题】: "基于JavaWeb的物资管理系统项目源码解析" 在Java毕设项目中,"javaWeb物资管理系统"是一个常见的选题,它涉及到多个JavaWeb技术的应用,旨在实现对物资的入库、出库、库存查询等管理功能。这个项目不仅...

    Android源码——超级清爽android计算器界面源码.zip

    在这里,我们可以学习如何编写响应用户输入的逻辑代码,例如将按钮的文本值附加到当前计算表达式,或者执行特定的计算操作。 计算逻辑是计算器的核心部分。这部分代码可能包含一个或多个类,负责解析用户输入的...

    dom4jdemo源码

    DOM4J是一个非常灵活的开源Java XML API,它提供了一套全面的XML处理解决方案,包括XML的解析、文档构建、XPath查询和事件处理等。DOM4J设计目标是简化XML在Java应用程序中的使用,尤其是在Java世界中,它作为一个轻...

    DOM4J 解析XML

    DOM4J的主要特点包括对XPath的支持、事件驱动的解析、以及与流行的Java框架(如Spring和Hibernate)的良好集成。 在解析XML时,DOM4J有两种主要的解析方式:SAX和DOM。SAX是一种基于事件的解析器,适用于处理大型...

    Android 英语朗读器源码.zip

    《Android 英语朗读器源码解析》 在当今移动设备盛行的时代,Android平台上的应用开发成为开发者的重要战场。本篇文章将深入探讨一个特定的Android应用项目——“英语朗读器”的源码,旨在帮助开发者理解并学习如何...

    最全Java注解图文超详解(建议收藏).pdf

    Java注解是Java编程语言中的一个重要特性,它允许程序员在代码中添加元数据,这些元数据可以被编译器、解释器或其他工具在编译时或运行时解析和使用。注解的主要目的是提供一种更安全、更方便的方式来为代码添加信息...

    java面试题总结!!!!!!!!!!!!!!!

    Java 类的加载过程包括加载、验证、准备、解析和初始化五个阶段。类加载器主要负责加载工作,Java 中主要有 Bootstrap ClassLoader(启动类加载器)、Extension ClassLoader(扩展类加载器)和 AppClassLoader(应用...

    疯狂XML讲义 源码8(1)

    《疯狂XML讲义》是一本深入探讨XML技术的权威书籍,源码8(1)则可能包含该书第八章的部分代码实例。XML(eXtensible Markup Language)是一种标记语言,设计用来传输和存储数据,尤其适用于网络环境。在本章节中,...

    dom4j 读取带有命名空间的xml文件

    如果需要创建新的XML元素并附加命名空间,可以使用`Element`类的`addNamespace()`方法,然后创建和添加元素。 ```java Namespace newNs = Namespace.get Namespace("newprefix", "http://example.com/newns"); ...

    Java虚拟机

    这本书的内容是帮你全面了解java虚拟机,本书第1版两年内印刷近10次,98%以上的评论全部为5星级的好评,是整个Java图书领域公认的经典著作和超级畅销书,繁体版在台湾也十分受欢迎。第2版在第1版的基础上做了很大的...

    android学习日记-4 JAVA注解总结

    3. Retrolambda:通过注解使Android项目支持Java 8的lambda表达式。 4. Room数据库:@Entity、@Dao、@Database等注解简化了SQLite数据库操作。 七、Android Studio支持 Android Studio提供了对注解的良好支持,包括...

    spring3.2.5源码包

    Spring 3.2.5是该框架的一个稳定版本,包含了多个核心模块和附加组件,旨在简化企业级应用程序的开发。让我们深入探讨一下这个版本中的关键知识点。 1. **核心容器**: - **Bean工厂(BeanFactory)**:这是Spring...

    超越微软自带计算器(源代码)

    这通常涉及到解析数学表达式的过程,可能采用了逆波兰表示法(RPN)或者解析树等算法。 标签中的“科学计算器”意味着这个程序具备科学计算的功能,比如支持对数、指数、平方根、立方根等,还有可能有角度和弧度...

    带抽屉滑动效果

    为了实现这样的功能,开发者可能需要编写一个解析器,将用户输入的中缀表达式转换为逆波兰表达式,然后使用一个栈来计算结果。这个过程涉及到字符串处理、栈数据结构的运用以及对数学运算的理解。 在提供的压缩包...

Global site tag (gtag.js) - Google Analytics