1 简介
jep是Java expression parser的简称,即java 表达式转换器。
能够将字符串
形式的公式
,配置对应的参数
得到计算结果。
属于比较老的项目,最新版本Jep 3.5,官网最后一次维护为2018年7月。
官网: http://www.singularsys.com/jep/
中文参考网站: https://www.ibm.com/developerworks/cn/java/j-lo-jep/
官网介绍如下:
Jep Java仅用几行代码解析和计算数学表达式。这个包允许用户以字符串的形式输入公式,并立即对其求值。Jep支持用户定义的变量、常量和函数。包括一些常用的数学函数和常量。
特性:
文件小巧 (小于400KB作为jar归档)
快速求值
使用bigdecimal的高精度
包括常用的数学函数和运算符
支持布尔表达式
可扩展和可配置的体系结构
支持字符串、向量和复数
支持隐式乘法
允许声明或未声明的变量
Java 1.7兼容的
支持Unicode字符
广泛的文档和>1400单元测试
本地化
2 使用
2.1 pom引用
maven仓库只有2.24
版本。
如想使用最新版本,需下载最新版本,打包到自己的本地maven仓库中或通过引入外部jar文件使用。
<dependency>
<groupId>jep</groupId>
<artifactId>jep</artifactId>
<version>2.24</version>
</dependency>
2.2 java案例
2.2.1 基本使用
String expression="(a+b)*b-1";
JEP jep=new JEP();
//1 设置变量
jep.addVariable("a",1);
jep.addVariable("b",2);
//2 计算表达式
jep.parseExpression(expression);
//3 获取表达式的值
double result=jep.getValue();
System.out.println(result);
//输出结果:5.0
其中需注意:
(1)第1、2步,操作不可颠倒,第2步计算表达式
之前需将参数全部设置好,否则无法正常结算。结果为0.0
。
(2)getValue()
结果为double
类型
(3)addVariable方法中的参数值类型为double,方法实现如下:
public Double addVariable(String var1, double var2) {
Double var4 = new Double(var2);
this.symTab.put(var1, var4);
return var4;
}
2.2.2 使用内置函数
JEP内置的函数有:标准函数、复数函数。
如使用内置函数sum
,需要先执行引入内置函数的方法
:addStandardFunctions
,才可调用内置函数。
示例代码如下:
JEP jep=new JEP();
//引入标准函数(必须先引入函数,才可执行对应内置方法)
jep.addStandardFunctions();
jep.parseExpression("sum(1,2)");
double result=jep.getValue();
System.out.println(result);
//输出结果:3.0
相关函数代码可参考源码:
可以看到,执行引入函数的方法,就是将系统内置的函数,加载到当前函数执行列表中
。
public void addStandardFunctions() {
this.funTab.put("sin", new Sine());
this.funTab.put("cos", new Cosine());
this.funTab.put("tan", new Tangent());
this.funTab.put("asin", new ArcSine());
this.funTab.put("acos", new ArcCosine());
this.funTab.put("atan", new ArcTangent());
this.funTab.put("sinh", new SineH());
this.funTab.put("cosh", new CosineH());
this.funTab.put("tanh", new TanH());
this.funTab.put("asinh", new ArcSineH());
this.funTab.put("acosh", new ArcCosineH());
this.funTab.put("atanh", new ArcTanH());
this.funTab.put("log", new Logarithm());
this.funTab.put("ln", new NaturalLogarithm());
this.funTab.put("sqrt", new SquareRoot());
this.funTab.put("angle", new Angle());
this.funTab.put("abs", new Abs());
this.funTab.put("mod", new Modulus());
this.funTab.put("sum", new Sum());
this.funTab.put("rand", new Random());
}
public void addStandardConstants() {
this.symTab.put("pi", new Double(3.141592653589793D));
this.symTab.put("e", new Double(2.718281828459045D));
}
public void addComplex() {
this.symTab.put("i", new Complex(0.0D, 1.0D));
this.funTab.put("re", new Real());
this.funTab.put("im", new Imaginary());
}
2.2.3 自定义函数
源码中提供方法addFunction
,用来自定义函数,自定义函数的写法,可参照系统默认函数类的写法
。
自定义函数类需继承PostfixMathCommand
类,并将此类注册到函数中。
代码示例如下:
//自定义函数类(非正数返回0)
public static class MyFun extends PostfixMathCommand{
public MyFun(){
//初始化参数格式(如参数个数为变长,测为-1)
super.numberOfParameters = 1;
}
@Override
public void run(Stack stack) throws ParseException {
//检查栈
this.checkStack(stack);
//出栈
Object obj = stack.pop();
//计算结果入栈
stack.push(this.myMethod(obj));
}
private Object myMethod(Object obj) throws ParseException{
if(obj instanceof Number){
double inputParam=((Number) obj).doubleValue();
if(inputParam<0){
return new Double("0.00");
}else{
return new Double(inputParam);
}
}else{
throw new ParseException("Invalid parameter type");
}
}
}
测试代码如下:
JEP jep=new JEP();
//引入标准函数
jep.addFunction("myFun01",new MyFun());
jep.parseExpression("myFun01(10)");
System.out.println(jep.getValue());
jep.parseExpression("myFun01(-9)");
System.out.println(jep.getValue());
//执行结果为10 0
方法addFunction源码如下:
public void addFunction(String var1, PostfixMathCommandI var2) {
this.funTab.put(var1, var2);
}
2.2.4 变量
(1)初始化系统级变量-源码
public void addStandardConstants() {
this.symTab.put("pi", new Double(3.141592653589793D));
this.symTab.put("e", new Double(2.718281828459045D));
}
(2)自定义变量-源码
public Double addVariable(String var1, double var2) {
Double var4 = new Double(var2);
this.symTab.put(var1, var4);
return var4;
}
3 特殊情况
3.1 错误判断
需注意,如果表达式不正确,或者缺少参数,或者其他导致计算错误的问题。代码并不会抛出异常。
可以通过hasError
方法判断是否执行出错;通过getErrorInfo
方法获取详细异常信息。
示例代码如下:
JEP jep=new JEP();
jep.parseExpression("1+x+2");
if(jep.hasError()){
System.out.println("计算出错-"+jep.getErrorInfo());
}else{
System.out.println("结果:"+jep.getValue());
}
//输出结果如下:计算出错-Unrecognized symbol "x"
3.2 连续运算符
**如数值之间,连续有几个同级别运算符
,所有运算符将全部生效
,计算不报错
;
如是非同级运算符,将报错
如下:
计算公式 | 结果 | 错误 |
---|---|---|
1+-2 | -1.0 | 无 |
1+--2 | 3.0 | 无 |
1+-*2 | Unexpected "*" at column 4. |
3 总结
比较小众的java表达式分析器,基本数学公式计算可以正常使用,满足日常绝大多数公式计算
。
功能有限,不建议生产复杂的计算环境使用,可以用来了解学习或者应用对数值计算要求不高的场景。
官方貌似已不再更新
,且之前发布版本已是long long ago的时候。以下为官方版本变更记录。
Current Release | Size | Release Date | |
---|---|---|---|
Jep Java 3.5 Trial | .zip | 4MB | Aug 4, 2018 |
Previous Releases | |||
Jep Java 3.4 Trial | .zip | 2.5MB | Nov 1, 2010 |
Jep Java 3.3 Trial | .zip | 2.2MB | Nov 30, 2008 |
Jep Java 3.2 Trial | .zip | 1.7MB | Feb 12, 2008 |
Jep Java 3.1 Trial | .zip | 1.5MB | Sep 23, 2007 |
Jep Java 3.0 Trial | .zip | 1.4MB | Jun 30, 2007 |
Jep Java 2.4.1 GPL | .zip | 2.5MB | Apr 25, 200 |