【表达式】JAVA解析数学表达式 parsii 计算数学公式 表达式规则引擎 动态脚本语言
1 MAVEN依赖
<!-- https://mvnrepository.com/artifact/com.scireum/parsii -->
<dependency>
<groupId>com.scireum</groupId>
<artifactId>parsii</artifactId>
<version>4.0</version>
</dependency>
或者使用 BigDecimal版本
<!-- https://mvnrepository.com/artifact/com.mpobjects/bdparsii -->
<dependency>
<groupId>com.mpobjects</groupId>
<artifactId>bdparsii</artifactId>
<version>1.0.0</version>
</dependency>
2 DEMO
String exp = "2 + (7-5) * 3.14159 * x + sin(0)";
// compile
Scope scope = Scope.create();
Expression parsiiExpr = Parser.parse(exp);
Variable var = scope.getVariable("x");
var.setValue(X_VALUE);
// evaluate
double result = parsiiExpr.evaluate();
//OR
//BigDecimal result = parsiiExpr.evaluate();
System.out.println(result);//-> 2.0
计算工具 支持%等
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import com.guanwei.study.string.CharUtil;
import com.mpobjects.bdparsii.eval.Expression;
import com.mpobjects.bdparsii.eval.Parser;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class ParsiiDemo {
public static void main(String[] args) throws Exception {
// String exp = "2 + (7-5) * 3.14159 * x + sin(0)";
String exp = "e^0.4*sign(3/12)";
exp = "((1+2 - 0) × 100 +( 2X1)-2 ) ÷2 * 50.5% * 20% + {1-2} + [1+5] ﹣1·1 /1 ﹢1 ﹣1";
// String exp = "e^0.4*√(3/12)";
System.out.println("之前:" + exp);
exp = ParsiiDemo.transitionFormula(exp);
System.out.println("之后:" + exp);
// compile
// Scope scope = new Scope();
Expression parsiiExpr = Parser.parse(exp);
// Variable var = scope.getVariable("x");
// var.setValue(0);
// evaluate
BigDecimal result = parsiiExpr.evaluate();
System.out.println("计算结果:" + result);//-> 2.0
}
public static String transitionFormula(String exp){
// exp = "+";
//全角转半角
exp = CharUtil.toDbc(exp);
//所有字符转为小写
exp = exp.toLowerCase();
exp = exp
.replaceAll("﹢", "+")
.replaceAll("十", "+")
.replaceAll("┼", "+")
.replaceAll("╋", "+")
.replaceAll("╬", "+")
.replaceAll("﹣", "-")
.replaceAll("一", "-")
.replaceAll("x", "*")
.replaceAll("×", "*")
.replaceAll("╳", "*")
.replaceAll("х", "*")
.replaceAll("·", "*")
.replaceAll("÷", "/")
.replaceAll("\\{", "(")
.replaceAll("}", ")")
.replaceAll("\\[", "(")
.replaceAll("]", ")")
;
//包含百分号
if(exp.contains("%")){
//获取包含百分号的数字
//List<String> resultFindAll = ReUtil.findAll("([\\d])*%|([\\d]).([\\d])*%", exp, 0, new ArrayList<String>());
List<String> resultFindAll = ReUtil.findAll("([\\\\d])*%|(\\\\d{1,10}).([\\\\d])*%", exp, 0, new ArrayList<String>());
if(CollUtil.isNotEmpty(resultFindAll)){
for (String s : resultFindAll) {
s = s.trim();
String replace = s.replace("%", "");
BigDecimal bigDecimal = new BigDecimal(replace);
bigDecimal = bigDecimal.divide(new BigDecimal(100));
exp = exp.replaceAll(s, bigDecimal.toString());
}
}
System.out.println(resultFindAll);
}
return exp;
}
}
补充全角转半角的工具
CharUtil
import cn.hutool.core.util.StrUtil;
/**
* 字符工具
*/
public class CharUtil {
/**
* 半角转全角的函数(SBC case)
* 全角空格为12288,半角空格为32,其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
*
* @param input 任意字符串
* @return 全角字符串
*/
public static String toSbc(String input) {
if (StrUtil.isBlank(input)) {
return "";
}
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == 32) {
c[i] = (char) 12288;
continue;
}
if (c[i] < 127) {
c[i] = (char) (c[i] + 65248);
}
}
return new String(c);
}
/**
* 全角转半角的函数(DBC case)
* 全角空格为12288,半角空格为32 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
*
* @param input 任意字符串
* @return 半角字符串
*/
public static String toDbc(String input) {
if (StrUtil.isBlank(input)) {
return "";
}
char[] c = input.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == 12288) {
c[i] = (char) 32;
continue;
}
if (c[i] > 65280 && c[i] < 65375) {
c[i] = (char) (c[i] - 65248);
}
}
return new String(c);
}
/**
* 打印出java中所有Unicode编码的字符
*/
private static void printAllCharacter() {
for (int i = Character.MIN_VALUE; i <= Character.MAX_VALUE; ++i) {
System.out.println(i + " " + (char) i);
}
}
public static void main(String[] args) {
String str = "半角符号示例:,!~ 全角符号示例:,!~";
System.out.println("半角--->全角转换前:" + str);
String sbcResult = toSbc(str);
System.out.println("半角--->全角转换后:" + sbcResult);
System.out.println("全角--->半角转换前:" + str);
String dbcResult = toDbc(str);
System.out.println("全角--->半角转换后:" + dbcResult);
//打印出java所有字符
// printAllCharacter();
}
}
其他
添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.2.7</version>
</dependency>
代码
ExpressRunner runner = new ExpressRunner();
DefaultContext<String, Object> context = new DefaultContext<String, Object>();
context.put("a",1);
context.put("b",2);
context.put("c",3);
String express = "a+b*c+3";
Object r = runner.execute(express, context, null, true, false);
System.out.println(r);
JEval
依赖
<!-- https://mvnrepository.com/artifact/net.sourceforge.jeval/jeval -->
<dependency>
<groupId>net.sourceforge.jeval</groupId>
<artifactId>jeval</artifactId>
<version>0.9.4</version>
</dependency>
代码
String exp = "2 + (7-5) * 3.14159 * #{x} + sin(0)";
// compile
Evaluator jevalEvaluator = new Evaluator();
jevalEvaluator.setVariables(Collections.singletonMap("x", Double.toString(X_VALUE)));
// evaluate
double result = Double.parseDouble(jevalEvaluator.evaluate(exp));
System.out.println(result);//-> 2.0
JEPLite
String exp = "2 + (7-5) * 3.14159 * x + sin(0)";
// compile
JEP jep = new JEP();
jep.addVariable("x", X_VALUE);
jep.parseExpression(exp);
DoubleStack jepStack = new DoubleStack();
// evaluate
double result = jep.getValue(jepStack);
System.out.println(result);//-> 2.0
parsii
JEval
JEPLite
expr
Janino
MathEval
QLExpress
QLExpress是一种功能强大、轻量级的Java平台动态语言,旨在提高开发人员在不同业务场景中的生产力。
由阿里的电商业务规则、表达式(布尔组合)、特殊数学公式计算(高精度)、语法分析、脚本二次定制等强需求而设计的一门动态脚本引擎解析工具。 在阿里集团有很强的影响力,同时为了自身不断优化、发扬开源贡献精神,于2012年开源。
QLExpress脚本引擎被广泛应用在阿里的电商业务场景,具有以下的一些特性:
- 1、线程安全,引擎运算过程中的产生的临时变量都是threadlocal类型。
- 2、高效执行,比较耗时的脚本编译过程可以缓存在本地机器,运行时的临时变量创建采用了缓冲池的技术,和groovy性能相当。
- 3、弱类型脚本语言,和groovy,javascript语法类似,虽然比强类型脚本语言要慢一些,但是使业务的灵活度大大增强。
- 4、安全控制,可以通过设置相关运行参数,预防死循环、高危系统api调用等情况。
- 5、代码精简,依赖最小,250k的jar包适合所有java的运行环境,在android系统的低端pos机也得到广泛运用。
groovy
Apache Groovy是一种强大的、可选的类型化和动态语言,具有静态类型和静态编译功能,用于Java平台,目的在于通过简洁、熟悉和易于学习的语法提高开发人员的工作效率。它可以与任何Java程序顺利集成,并立即向您的应用程序提供强大的功能,包括脚本编写功能、特定于域的语言编写、运行时和编译时元编程以及函数式编程。
Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。也是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程
流程规则引擎
dromara / liteFlow
轻量,快速,稳定,可编排的组件式规则引擎/流程引擎。 拥有全新设计的DSL规则表达式。 组件复用,同步/异步编排,动态编排,复杂嵌套规则,热部署,平滑刷新规则等等功能,让你加快开发效率!