mathematical-expression 实现 数学表达式解析 Java 篇

mathematical-expression 实现 数学表达式解析 Java 篇

Java技术栏
使用 ME( mathematical-expression)数学表达式解析库 实现Java中 数学表达式 的解析和计算。

目录

文章目录

  • mathematical-expression 实现 数学表达式解析 Java 篇
    • 目录
    • mathematical-expression 介绍
      • 获取到 ME 组件
        • Maven依赖坐标
        • Gradle 依赖坐标
        • ME 组件存储库
      • ME 组件结构
        • 无括号数学表达式计算组件
        • 有括号的数学表达式计算
        • 比较运算表达式
        • 函数计算表达式
        • 多参函数计算组件
      • 高阶操作
        • 数学方式的函数注册与计算
        • 匿名实现的函数注册于计算


在这里插入图片描述

mathematical-expression 介绍

在计算机中,本身并不存在数学表达式的概念,数学表达式其本身是在人类世界中对于逻辑的一种总结规范,计算机并不了解这些公式中的符号,因此对于数学表达式也需要一个编译器,就像编程语言到机器码之间的编译器一样,mathematical-expression 是一种针对数学公式解析的有效工具,能够解析包含嵌套函数,包含函数,数列步长累加等数学公式,返回值是一个数值的结果对象,同时也可以进行比较运算的操作,再进行比较的时候,返回值是一个布尔值结果对象。

获取到 ME 组件

ME 组件的获取有诸多方式,接下来您可以根据需求选择您需要的方式来实现 ME 组件的获取与装载。

PS 请尽量使用 1.3.1 版本以及以上的版本,这将有助于您使用更加稳定的版本,修复了 1.2.x 版本中所有已知的bug

Maven依赖坐标

您可以直接使用maven将本框架导入到项目中使用,能够高效的使用该功能

<dependencies>
    <dependency>
        <groupId>io.github.BeardedManZhao</groupId>
        <artifactId>mathematical-expression</artifactId>
        <version>1.3.1</version>
    </dependency>
</dependencies>
Gradle 依赖坐标

您也可以直接通过gradle将“mathematical-expression”载入到您的框架中,使用下面的依赖即可。

dependencies {
    implementation 'io.github.BeardedManZhao:mathematical-expression:1.3.1'
}
ME 组件存储库

您还可以在 ME 组件存储库 历史存档馆 中获取到您需要的版本对应的所有资源。

ME 组件结构

ME 组件主要由三个部分组成,分别是数据存储对象,以及,解析与计算对象,还有计算管理者,他们分别负责不同的任务和位置,共同配合,实现强大的计算操作。



Created with Rapha?l 2.3.0
















































数学表达式





从管理者获取到计算组件





检查表达式



检查是否通过?



是否能够支持这类数学表达式的解析?



是否实现共享池?



计算操作正常?





封装计算结果与计算信息





计算完毕,封装结果





发生异常



解析是否通过?



yes



no



yes



no



yes



no



yes



no



yes



no

接下来我们将进行实际的演示,讲述如何在 Java 中快速且方便的处理数学表达式。

无括号数学表达式计算组件

此组件顾名思义,就是用于没有括号的数学表达式的解析和计算中,此计算组件是所有计算组件的祖先,具有更简单的结构以及计算性能



Created with Rapha?l 2.3.0

































开始计算



是否提取完毕





结果汇总





提取操作数





提取运算符



是否为高优先级





计算临时结果





临时存储



yes



no



yes



no

但面对复杂的计算表达式,此计算组件将无法体现出其灵活性,下面是有关该表达式的一个操作示例。

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
有括号的数学表达式计算

带有括号的数学计算表达式,是最常用的一种计算组件,其能够实现有效的数学表达式优先级计算操作,计算的复杂度也不会太高,下面就是结果



Created with Rapha?l 2.3.0
























开始计算



是否包含括号





提取子表达式





无括号表达式计算 1or2 级计算





结果汇总





数值结果封装



yes



no

在库中诸多的计算组件都是基于此组件进行拓展的,下面就是一个使用示例。

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
比较运算表达式

基于 有括号 计算组件的一种拓展,在这里我们可以针对两个数学表达式进行比较,在这里的比较操作中,能够实现有效的比较运算,返回值是 布尔 类型的结果对象,它的计算过程如下所示。



Created with Rapha?l 2.3.0
























开始计算



左右解析(yes代表左)





获取左边表达式





有括号表达式计算 N级计算





布尔比较计算 N+1级计算





获取右边表达式



yes



no

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() + "	计算结果:" + calculation.getResult() +
                        "	计算来源:" + 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 库中,允许使用一些函数来进行计算操作,数学表达式中的函数在这里也可以实现,通过自定义实现函数的方式,能够封装计算逻辑,且有效的提升灵活性,其计算复杂度并不高,也是比较常用的计算组件。



Created with Rapha?l 2.3.0







































开始计算





提取函数



函数是否存在





提取函数形参





有括号表达式计算 N级计算





计算结果传递





函数内部计算





结果存储



函数是否提取完毕





有括号表达式计算 结果汇总





发生异常



yes



no



yes



no

接下来就是相关的使用演示!!!

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()+"	计算结果:"+calculation.getResult()+
                        "	计算来源:"+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()+"	计算结果:"+calculation.getResult()+
                        "	计算来源:"+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'}

  • 相关文章
    《mathematical-expression 实现 数学表达式解析 C++ 篇》
    《公共API-数学表达式计算:mathematical-expression-JS篇》