文档章节

Java处理数学公式得出结果

杨润康Bla
 杨润康Bla
发布于 2016/05/18 18:04
字数 1029
阅读 50
收藏 1

支持含有字母的复杂表达式、不含字母的纯数学表达式

先上测试程序,后面有源码:
1.纯数字的算式测试

    public static void main(String[] args) throws Exception {
        String express = "(100-5+45)*88.8/(5/94+584)";
        Double result = MathFormulaUtil.getNumberResult(express);
        System.out.println(result); //结果:21.28573250031876
    }

2.带有字母的公式测试

public static void main(String[] args) throws Exception {
        String express = "(((x+y)/(z+x)*q)+100-99)*565";
        //输入参数
        double[] param = new double[]{45,89,200,45,66};
        Double result =MathFormulaUtil.getExpressionResult(express, param);
        System.out.println(result); //结果:20960.346938775518
    }

下面是程序源码:

/* 说明: 首先需要导入2个jar包: expression4jCFG.jar expression4j.jar 上面2个jar包依赖于日志记录,所以还需要导入下面几个日志包. slf4j-api-1.5.11.jar log4j-1.2.17.jar slf4j-log4j12-1.5.11.jar 上面的jar包在文章的末尾有下载 */
package com.usi.jrwl.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import fr.expression4j.basic.MathematicalElement;
import fr.expression4j.core.Expression;
import fr.expression4j.core.Parameters;
import fr.expression4j.factory.ExpressionFactory;
import fr.expression4j.factory.NumberFactory;
/** * 输入数学公式即可计算结果 * @author 杨润康 */
public class MathFormulaUtil {

    /** * 根据用户输入的数学算式返回表达式对象 * @param expressionString 用户输入 数学算式 * @param params 按照变量的位置为变量输入[对应]的值 * @return 计算结果 * @throws Exception * * note:在英文输入法的状态下输入 */
    public static Double getExpressionResult(String expressionString,double...params) throws Exception{
        // ( ) + - * / 0-9是数学中的表达式 其余的部分是变量 x y z 等等
        //注意消除空格
        //第一步 去除空格
        expressionString.trim().replace(" ","");
        //第二步 获取每个字符串的每个字符 后面主要做过滤
        String[] expressArgs = expressionString.split("");
        //创建过滤器 过滤出来除 ( ) + - * / 数字 0-9 之外的其余字符
        List<String> filters = Arrays.asList("(",")","+","-","*","/","0","1","2","3","4","5","6","7","8","9");
        //过滤出结果 即过滤出用户输入的变量
        List<String> vars = new ArrayList<String>();//存放过滤结果 
        int count = -1;
        for(String arg : expressArgs){
            count++; //计数 从0
            if(!filters.contains(arg)){ //字符不在工具类中
                if(!arg.equals("")){  //空格不能加入其中 
                    //处理重复变量的问题
                    if(vars.contains(arg)){ //如果已经过滤的结果中包含了当前循环的编号 追加随机数 避免让key值不一样,这样不会发生替换
                        String argRandom = arg+getRandom(); // f(x,x12) 中变了,还得让 = (x+x2)中对应的变量也变 处理方法 count
                        //替换原表达式,即等号后面的部分
                        String oldChar = expressionString.substring(count-1); //等号 替换循环位置后面的部分 后面原字符
                        //不能直接替换 这样会都替换掉 我只是替换循环位置后面的部分
                        String repStrLater = oldChar.replace(oldChar, argRandom);
                        //更新等号后面的表达式 截掉旧的替换新的
                        expressionString = expressionString.substring(0,count-1)+repStrLater+expressionString.substring(count);
                        vars.add(argRandom);
                        count = count +32; //补充随机字符串的剩余长度,,以保证坐标准确
                    }else{ //不包含 正常添加
                        vars.add(arg);
                    }
                }
            }
        }
        //构建表达式 "f(x,y,z,..)="
        StringBuilder expressionHead = new StringBuilder("f(");
        for(String v : vars){
            expressionHead.append(v+",");
        }
        //将最后一个 , 去掉
        expressionHead.setLength(expressionHead.length()-1);
        expressionHead.append(")=");
        //完整的表达式
        String expressionAll = expressionHead + expressionString;
        //创建表达式对象
        Expression expression = ExpressionFactory.createExpression(expressionAll);

        //为参数赋值放入List中 顺序不能乱
        List<MathematicalElement> mes = new ArrayList<MathematicalElement>();

        //输入的参数 params
        //构建数学元素
        for (int i = 0; i < params.length; i++) {
            mes.add(NumberFactory.createReal(params[i]));
        }

        //从表达式工厂创建一个空的参数
        Parameters parameters = ExpressionFactory.createParameters();
        //对应参数赋值
        for(int i=0;i<vars.size();i++){
            //这边是键值的形式存储的,所以第二个,传过来的第二个x的值,或由于键是一样的,而替换掉第一次键对应的值,及2--->4,键还是那个键 x
            //解决方法 键的区分 : 过滤用户表达式中的变量时加一个方法 即 与已经过滤出来结果再此比较,如果在出现一样的键,重新命名采用追加随机数的方式 
            parameters.addParameter(vars.get(i),mes.get(i));//vars 变量 mes 变量对应的值 
        }
        //返回结果
        return expression.evaluate(parameters).getRealValue();
    }

    /** * 支持纯数字计算 * @param expressionString 用户输入 数学算式 * @return 计算结果 * @throws Exception 异常 */
    public static Double getNumberResult(String expressionString) throws Exception{
        Expression expression = ExpressionFactory.createExpression("f()="+expressionString);
        return expression.evaluate(null).getRealValue();
    }

    /** * 生成随机数 */
    public  static String getRandom(){
        String s = UUID.randomUUID().toString();
        return s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24);
    }
}

jar包下载地址:http://sourceforge.net/projects/expression4j/

本文转载自:http://blog.csdn.net/yangrunkangbla/article/details/50222063

共有 人打赏支持
杨润康Bla
粉丝 14
博文 76
码字总数 0
作品 0
合肥
后端工程师
Java利用ScriptEngineManager对计算公式的支持

1、ScriptEngineManager是JDK6提出的相关方法,这方式的主要目的就是用来对脚本语言的处理。这里只是简单介绍一下对我们常用的数学公式的应用。 2、ScriptEngineManager是在java的javax.scr...

小不点丶
2017/10/26
0
0
Scala和Java在多核处理性能的一次对比和思考

今天在网络上看到了一篇关于Scala和java多线程对比的文章《Simple Scala actor Vs java Thread Vs Kilim Test,原文链接:http://www.blogjava.net/BlueDavy/archive/2009/11/25/303662.html......

qinhui99
2012/05/13
0
3
Scala学习笔记(2)-基础语法

秉着简洁而不失完整的的原则,这章只把Scala主要语法和与Java不同的内容列出来,以后章节也如此,内容以简洁为主,太长了自己都被吓着了,也没耐心看下去。 1.Scala解释器使用,这里不做介绍...

山海经
2013/08/25
0
0
【转】JDK,JRE,JVM三者之间的关系

如果安装了JDK,会发同你的电脑有两套JRE,一套位于 jre 另外一套位于 C:Program FilesJavaj2re1.4.1_01 目录下,后面这套比前面那套少了Server端的Java虚拟机,不过直接将前面那套的Server端...

mj4738
2012/01/15
0
0
一个java初学者的心得体验!

学习了一学期的Java课程,觉得是该总结自己的心得体会了。开始学习任何一门课(包括java),兴趣最重要。 还记得我编写的第一个经典程序“Hello Word”。从那时起我已开始走进Java的世界。 当时...

嘿你好夏天
01/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何通过 J2Cache 实现分布式 session 存储

做 Java Web 开发的人多数都会需要使用到 session (会话),我们使用 session 来保存一些需要在两个不同的请求之间共享数据。一般 Java 的 Web 容器像 Tomcat、Resin、Jetty 等等,它们会在...

红薯
今天
3
0
C++ std::thread

C++11提供了std::thread类来表示一个多线程对象。 1,首先介绍一下std::this_thread命名空间: (1)std::this_thread::get_id():返回当前线程id (2)std::this_thread::yield():用户接口...

yepanl
今天
3
0
Nignx缓存文件与动态文件自动均衡的配置

下面这段nginx的配置脚本的作用是,自动判断是否存在缓存文件,如果有优先输出缓存文件,不经过php,如果没有,则回到php去处理,同时生成缓存文件。 PHP框架是ThinkPHP,最后一个rewrite有关...

swingcoder
今天
2
0
20180920 usermod命令与用户密码管理

命令 usermod usermod 命令的选项和 useradd 差不多。 一个用户可以属于多个组,但是gid只有一个;除了gid,其他的组(groups)叫做扩展组。 usermod -u 1010 username # 更改用户idusermod ...

野雪球
今天
3
0
Java网络编程基础

1. 简单了解网络通信协议TCP/IP网络模型相关名词 应用层(HTTP,FTP,DNS等) 传输层(TCP,UDP) 网络层(IP,ICMP等) 链路层(驱动程序,接口等) 链路层:用于定义物理传输通道,通常是对...

江左煤郎
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部