JEP
是一个用于解析和计算数学表达式的
Java
类库。通过使用这个包你可以把公式看
作字符串并快速计算它们。其中内置了大量公共的数学函数和常量供用户使用。另外,你也
可以通过自定义变量、常量、函数等方式扩展
JEP
。
使用
JEP
计算一个字符串表达式包括两个步骤,如下图所示。首先是解析表达式,从
字符串结构解析为树形结构。表达式的树形结构表示允许接下来的简单、快速的表达式计算。
![](https://i-blog.csdnimg.cn/blog_migrate/a93c1464002d32ae76145e130d24d118.png)
文档:Jep说明文档_jep,javajep-Java文档类资源-CSDN下载
测试代码:
<!-- jep java表达式分析器 -->
<dependency>
<groupId>com.singularsys</groupId>
<artifactId>jep</artifactId>
<version>3.5</version>
<classifier>trial</classifier>
</dependency>
import com.singularsys.jep.PostfixMathCommandI;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author lihai
* Create Date: 2021-11-20
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JepFunctionPo {
private String name;
private PostfixMathCommandI function;
}
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.qms.ipqc.common.po.JepFunctionPo;
import com.quality.common.exception.DangerException;
import com.quality.common.exception.GeneralException;
import com.singularsys.jep.Jep;
import com.singularsys.jep.JepException;
import com.singularsys.jep.Variable;
import com.singularsys.jep.VariableTable;
import com.singularsys.jep.bigdecimal.BigDecComponents;
import com.singularsys.jep.functions.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author lihai
* Create Date: 2021-11-20
*/
public class JepAnalysisUtil {
public static List<JepFunctionPo> getDefaultJepFunctionPoList() {
return Arrays.asList(
// new JepFunctionPo("round", new Round()),
// new JepFunctionPo("rint", new RInt()),
// new JepFunctionPo("floor", new Floor()),
// new JepFunctionPo("ceil", new Ceil()),
// new JepFunctionPo("abs", new Abs()),
new JepFunctionPo("sqrt", new SquareRoot()),
new JepFunctionPo("SQRT", new SquareRoot())
);
}
public static Jep newJep(List<JepFunctionPo> functions) {
Jep jep = new Jep(new BigDecComponents(MathContext.DECIMAL128));
if (ObjectUtil.isNotEmpty(functions)) {
functions.forEach(function -> jep.addFunction(function.getName(), function.getFunction()));
}
return jep;
}
public static Jep parse(String expression) {
Jep jep = newJep(getDefaultJepFunctionPoList());
try {
jep.parse(expression);
return jep;
} catch (Exception e) {
throw new DangerException("JEP解析表达式失败:" + expression + ",请检查表达式是否合法!");
}
}
public static BigDecimal analysis(String expression, Map<String, Object> variables) {
Jep jep = parse(expression);
try {
if (ObjectUtil.isNotEmpty(variables)) {
variables.forEach((k, v) -> {
try {
jep.addVariable(k, NumberUtil.parseNumber(v.toString()));
} catch (JepException e) {
throw new DangerException("JEP赋值异常:" + e.getMessage());
}
});
}
return new BigDecimal(jep.evaluate().toString());
} catch (JepException e) {
throw new GeneralException("JEP计算异常:" + e.getMessage());
}
}
public static Set<String> getVariables(String expression) {
Jep jep = parse(expression);
try {
final VariableTable variableTable = jep.getVariableTable();
final List<Variable> variables = new ArrayList<>(variableTable.getVariables());
return variables.stream().filter(var -> var.getValue() == null).map(Variable::getName).collect(Collectors.toSet());
} catch (Exception e) {
throw new DangerException("获取JEP变量失败:" + expression);
}
}
public static void checkExpressionVariables(String expression, Set<String> variables) {
final Set<String> expressionVariables = getVariables(expression);
for (String var : expressionVariables) {
if (!variables.contains(var)) {
throw new DangerException(String.format("表达式:%s 缺少变量:%s", expression, var));
}
}
}
}
测试方法:
@Test
void jepAnalysis() {
String expression = "sqrt(a-b+c*d/e)";
Map<String, Object> params = new HashMap<String, Object>() {{
put("a", 5);
put("b", 1);
put("c", 3);
put("d", 2);
put("e", 2);
}};
final BigDecimal analysis = JepAnalysisUtil.analysis(expression, params);
System.out.println("计算结果:" + analysis);
}