Java技术栏
使用 ME( mathematical-expression)数学表达式解析库 实现Java中 数学表达式 的解析和计算。
在计算机中,本身并不存在数学表达式的概念,数学表达式其本身是在人类世界中对于逻辑的一种总结规范,计算机并不了解这些公式中的符号,因此对于数学表达式也需要一个编译器,就像编程语言到机器码之间的编译器一样,mathematical-expression 是一种针对数学公式解析的有效工具,能够解析包含嵌套函数,包含函数,数列步长累加等数学公式,返回值是一个数值的结果对象,同时也可以进行比较运算的操作,再进行比较的时候,返回值是一个布尔值结果对象。
ME 组件的获取有诸多方式,接下来您可以根据需求选择您需要的方式来实现 ME 组件的获取与装载。
PS 请尽量使用 1.3.1 版本以及以上的版本,这将有助于您使用更加稳定的版本,修复了 1.2.x 版本中所有已知的bug
您可以直接使用maven将本框架导入到项目中使用,能够高效的使用该功能
<dependencies>
<dependency>
<groupId>io.github.BeardedManZhao</groupId>
<artifactId>mathematical-expression</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
您也可以直接通过gradle将“mathematical-expression”载入到您的框架中,使用下面的依赖即可。
dependencies {
implementation 'io.github.BeardedManZhao:mathematical-expression:1.3.1'
}
您还可以在 ME 组件存储库 历史存档馆 中获取到您需要的版本对应的所有资源。
ME 组件主要由三个部分组成,分别是数据存储对象,以及,解析与计算对象,还有计算管理者,他们分别负责不同的任务和位置,共同配合,实现强大的计算操作。
接下来我们将进行实际的演示,讲述如何在 Java 中快速且方便的处理数学表达式。
此组件顾名思义,就是用于没有括号的数学表达式的解析和计算中,此计算组件是所有计算组件的祖先,具有更简单的结构以及计算性能
但面对复杂的计算表达式,此计算组件将无法体现出其灵活性,下面是有关该表达式的一个操作示例。
public class MAIN {
public static void main(String[] args) {
// 准备一个数学表达式
String s1 = "1 + 20 * 2 + 4";
// 获取到无括号数学表达式
final Calculation instance = Mathematical_Expression.getInstance(Mathematical_Expression.prefixExpressionOperation);
// 开始进行检查
try {
instance.check(s1);
// 如果没有异常就直接进行计算
final CalculationNumberResults calculation = (CalculationNumberResults) instance.calculation(s1);
// 打印结果
System.out.println(calculation.getResult());
} catch (WrongFormat e) {
System.out.println("表达式错误,原因: " + e);
}
}
}
最终计算结果
45.0
进程已结束,退出代码0
带有括号的数学计算表达式,是最常用的一种计算组件,其能够实现有效的数学表达式优先级计算操作,计算的复杂度也不会太高,下面就是结果
在库中诸多的计算组件都是基于此组件进行拓展的,下面就是一个使用示例。
public class MAIN {
public static void main(String[] args) {
// 准备一个数学表达式
String s1 = "1 + 20 * (2 + 4)";
// 获取到有括号数学表达式
final Calculation instance = Mathematical_Expression.getInstance(Mathematical_Expression.bracketsCalculation2);
// 开始进行检查
try {
instance.check(s1);
// 如果没有异常就直接进行计算
final CalculationNumberResults calculation = (CalculationNumberResults) instance.calculation(s1);
// 打印结果
System.out.println(calculation.getResult());
} catch (WrongFormat e) {
System.out.println("表达式错误,原因: " + e);
}
}
}
最终计算结果
121.0
进程已结束,退出代码0
基于 有括号 计算组件的一种拓展,在这里我们可以针对两个数学表达式进行比较,在这里的比较操作中,能够实现有效的比较运算,返回值是 布尔 类型的结果对象,它的计算过程如下所示。
public class MAIN {
public static void main(String[] args) throws WrongFormat {
// 获取一个计算数学比较表达式的组件
final Calculation instance = Mathematical_Expression.getInstance(Mathematical_Expression.booleanCalculation2);
// 创建3个表达式
String s1 = "1 + 2 + 4 * (10 - 3)";
String s2 = "2 + 30 + (2 * 3) - 1";
String s3 = "1 + 3 * 10";
extracted(instance, s1 + " > " + s2);// false
extracted(instance, s1 + " < " + s2);// true
extracted(instance, s1 + " = " + s3);// true
extracted(instance, s1 + " == " + s3);// true
extracted(instance, s1 + " != " + s3);// false
extracted(instance, s1 + " <> " + s3);// false
extracted(instance, s1 + " <= " + s3);// true
extracted(instance, s1 + " >= " + s3);// true
extracted(instance, s1 + " != " + s2);// true
extracted(instance, s1 + " <> " + s2);// true
}
private static void extracted(Calculation booleanCalculation2, String s) throws WrongFormat {
// 检查表达式是否有错误
booleanCalculation2.check(s);
// 开始计算结果
CalculationBooleanResults calculation = (CalculationBooleanResults) booleanCalculation2.calculation(s);
// 打印结果数值
System.out.println(
"计算层数:" + calculation.getResultLayers() + "\t计算结果:" + calculation.getResult() +
"\t计算来源:" + calculation.getCalculationSourceName()
);
}
}
下面就是计算结果,可以看到这里返回的结果是一个 布尔 类型的结果对象
计算层数:4 计算结果:false 计算来源:booleanCalculation2
计算层数:4 计算结果:true 计算来源:booleanCalculation2
计算层数:3 计算结果:true 计算来源:booleanCalculation2
计算层数:3 计算结果:true 计算来源:booleanCalculation2
计算层数:3 计算结果:false 计算来源:booleanCalculation2
计算层数:3 计算结果:false 计算来源:booleanCalculation2
计算层数:3 计算结果:true 计算来源:booleanCalculation2
计算层数:3 计算结果:true 计算来源:booleanCalculation2
计算层数:4 计算结果:true 计算来源:booleanCalculation2
计算层数:4 计算结果:true 计算来源:booleanCalculation2
进程已结束,退出代码0
在 ME 库中,允许使用一些函数来进行计算操作,数学表达式中的函数在这里也可以实现,通过自定义实现函数的方式,能够封装计算逻辑,且有效的提升灵活性,其计算复杂度并不高,也是比较常用的计算组件。
接下来就是相关的使用演示!!!
public class MAIN {
public static void main(String[] args) throws WrongFormat {
// 实例化一个函数 名为DoubleValue 用于将一个数值乘2
ManyToOneNumberFunction myFunction = new ManyToOneNumberFunction("DoubleValue") {
@Override
public double run(double... numbers) {
// 在这里的参数中,第一个参数就是被FunctionFormulaCalculation所传入的参数
return numbers[0] * 2;
}
};
// 将函数注册到管理者中
CalculationManagement.register(myFunction);
// 获取一个计算累加数学表达式的组件
FunctionFormulaCalculation functionFormulaCalculation = FunctionFormulaCalculation.getInstance("zhao");
// 构建一个数学表达式,表达式中使用到了函数 DoubleValue
String s = "2 * DoubleValue(2 + 3) + 1";
// 检查数学表达式
functionFormulaCalculation.check(s);
// 计算结果
CalculationNumberResults calculation = functionFormulaCalculation.calculation(s);
System.out.println(
"计算层数:"+calculation.getResultLayers()+"\t计算结果:"+calculation.getResult()+
"\t计算来源:"+calculation.getCalculationSourceName()
);
}
}
在这里就是相关的计算结果
计算层数:1 计算结果:21.0 计算来源:BracketsCalculation2
进程已结束,退出代码0
从 ME 库 1.1 版本开始 针对函数数学表达式的计算将不再限制于只能传递一个参数,而是可以传递无数个参数,每个参数会在函数中以函数形参的格式进入到函数对象并进行计算,接下来就是相关的实际演示。
public class MAIN {
public static void main(String[] args) throws WrongFormat {
// 实现一个sum函数 用于将数值求和
ManyToOneNumberFunction manyToOneNumberFunction = new ManyToOneNumberFunction("sum") {
@Override
public double run(double... numbers) {
double res = 0;
for (double number : numbers) {
res += number;
}
System.out.println("调用函数 sum(" + Arrays.toString(numbers) + ") = " + res);
return res;
}
};
// 将该函数注册到管理者
CalculationManagement.register(manyToOneNumberFunction);
// 获取到新版本中的多参数学表达式解析组件
Calculation functionFormulaCalculation = Mathematical_Expression.getInstance(
Mathematical_Expression.functionFormulaCalculation2
);
// 构建一个数学表达式,表达式中使用到了函数 sum
String s = "2 * sum(2 + 3, 1 + 20, 10 + (1 - 2)) + 1";
// 检查数学表达式
functionFormulaCalculation.check(s);
// 计算结果
CalculationNumberResults calculation = (CalculationNumberResults) functionFormulaCalculation.calculation(s);
System.out.println(
"计算层数:"+calculation.getResultLayers()+"\t计算结果:"+calculation.getResult()+
"\t计算来源:"+calculation.getCalculationSourceName()
);
}
}
在这里就是相关的计算结果
调用函数 sum([5.0, 21.0, 9.0]) = 35.0
计算层数:1 计算结果:71.0 计算来源:BracketsCalculation2
进程已结束,退出代码0
package top.lingyuzhao;
import core.Mathematical_Expression;
import core.calculation.Calculation;
import core.calculation.function.FunctionPackage;
import exceptional.WrongFormat;
public class MAIN {
public static void main(String[] args) throws WrongFormat {
// 将 f 函数注册进来
Mathematical_Expression.register_function("f(x) = x * x");
// 准备要计算的表达式
final String data = "1 + f(20) + 3";
// 获取到计算组件
final Calculation instance = Mathematical_Expression.getInstance(Mathematical_Expression.functionFormulaCalculation2);
// 检查与计算
instance.check(data);
System.out.println(instance.calculation(data));
}
}
下面就是计算结果
CalculationNumberResults{result=404.0, source='BracketsCalculation2'}
package top.lingyuzhao;
import core.Mathematical_Expression;
import core.calculation.Calculation;
import core.calculation.function.FunctionPackage;
import core.calculation.function.ManyToOneNumberFunction;
import exceptional.WrongFormat;
public class MAIN {
public static void main(String[] args) throws WrongFormat {
// 将 f 函数注册进来
Mathematical_Expression.register_function(new ManyToOneNumberFunction("f") {
@Override
public double run(double... numbers) {
return 1 + numbers[0] * numbers[0] + 3;
}
});
// 准备要计算的表达式
final String data = "1 + f(20) + 3";
// 获取到计算组件
final Calculation instance = Mathematical_Expression.getInstance(Mathematical_Expression.functionFormulaCalculation2);
// 检查与计算
instance.check(data);
System.out.println(instance.calculation(data));
}
}
下面就是计算结果
CalculationNumberResults{result=408.0, source='BracketsCalculation2'}