栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java实现常用加减乘除公式解析及计算

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java实现常用加减乘除公式解析及计算

近期接到一个实现公式解析计算、能够多层嵌套并自动拆解的需求。即对于给定的字符串公式进行解析及计算,实现从持久层自动装载公式,拆解多层嵌套的公式,得到计算结果。大致的设计思路为:定义一个计算器基类,实现基本属性的装载及加减乘除公式的定义,实现公式拆解、运算符分级及解析计算;定义子类实现不同的装载逻辑和公式解析逻辑。

基类:

package cn.ac.sict.calculator;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class Calculator {
    //公式id
    private String id;
    //公式名称
    private String name;
    //公式内容
    private String formula;
    //公式类型,true代表formula为数值,false代表formula为计算公式
    private boolean type = false;
    //计算精度
    public static int precision = 0;
    //默认值
    public static String defaultValue = "0";
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getFormula() {
        return formula;
    }
    public void setFormula(String formula) {
        //把公式中的负数都转化为0-N的形式,方便计算
        if(isValidString(formula)) {
            StringBuffer stringBuffer = new StringBuffer();
            //匹配公式开头的负数部分或中间的负数部分,即以-开头或-前为其他运算符号
            Matcher matcher = Pattern.compile("(^-\d+\.?\d*)|([\(\+\-\*\/]{1}-\d+\.?\d*)").matcher(formula);
            int start = 0;
            while(matcher.find()) {
                String group = matcher.group();
                String replacement;
                if(group.charAt(1) >= '0' && group.charAt(1) <= '9') {
                    replacement = "(0" + group + ")";
                } else {
                    replacement = group.substring(0, 1) + "(0" + group.substring(1) + ")";
                }
                stringBuffer.append(formula, start, matcher.start()).append(replacement);
                start = matcher.end();
            }
            stringBuffer.append(formula, start, formula.length());
            this.formula = stringBuffer.toString();
        } else {
            this.formula = defaultValue;
        }
    }
    public boolean isType() {
        return type;
    }
    public void setType(boolean type) {
        this.type = type;
    }
    protected Calculator() {
    }
    
    private static boolean isValidString(String string) {
        return string != null && !"".equals(string) && !"null".equalsIgnoreCase(string);
    }
    
    private static boolean isValidDigit(String value) {
        if(isValidString(value)) {
            value = value.trim();
            return Pattern.compile("^(\+|-)?\d+($|\.\d+$)").matcher(value).matches();
        } else {
            return false;
        }
    }
    
    private static String format(String value) {
        StringBuffer expression = new StringBuffer("0");
        if(precision > 0) {
            expression.append(".");
            for(int i=0;i splitFormula() {
        int length = formula.length();
        List result = new ArrayList<>(length);
        StringBuffer item = new StringBuffer();
        for(int i=0;i 0) {
                    result.add(item.toString());
                    item.setLength(0);
                }
                item.append(c);
                result.add(item.toString());
                item.setLength(0);
            } else if((c >= '0' && c <= '9') || c == '#' || c == '.') {
                item.append(c);
            }
        }
        if(item.length() > 0) {
            result.add(item.toString());
        }
        return result;
    }
    
    public abstract void init();
    
    public abstract List parseFormula();
    
    public static String calculate(List list) {
        if(list == null || list.size() == 0) {
            return defaultValue;
        }
        Stack operatorStack = new Stack<>();
        Stack numberStack = new Stack<>();
        int size = list.size();
        for(int i=0;i= 2 && operatorStack.size() >= 1 && getPriority(str) <= getPriority(operatorStack.peek())) {
                    String operator = operatorStack.pop();
                    String right = numberStack.pop();
                    String left = numberStack.pop();
                    numberStack.push(calculate(left, right, operator));
                }
                operatorStack.push(str);
                if(")".equals(str)) {
                    while(!"(".equals(operatorStack.peek())) {
                        operatorStack.pop();
                    }
                    operatorStack.pop();
                }
            }
        }
        while(numberStack.size() >= 2 && operatorStack.size() >= 1) {
            String operator = operatorStack.pop();
            String right = numberStack.pop();
            String left = numberStack.pop();
            numberStack.push(calculate(left, right, operator));
        }
        return numberStack.pop();
    }
}

解析json格式数据的子类:

package cn.ac.sict.calculator;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class CalculatorJsonImpl extends Calculator {
    public String filePath = "D:\ide\project\Calculator\cn\ac\sict\calculator\data.json";
    private CalculatorJsonImpl() {
        super();
    }
    
    public static CalculatorJsonImpl create(String id) {
        CalculatorJsonImpl result = new CalculatorJsonImpl();
        result.setId(id);
        return result;
    }
    
    @Override
    public void init() {
        JSONArray jsonArray = JSONUtil.readJSONArray(new File(filePath), CharsetUtil.charset("UTF-8"));
        jsonArray.stream().forEach(obj -> {
            JSONObject jsonObject = JSONUtil.parseObj(obj);
            if(getId().equals(jsonObject.getStr("id"))) {
                setName(jsonObject.getStr("name"));
                setFormula(jsonObject.getStr("formula"));
                setType(jsonObject.getBool("type"));
            }
        });
    }
    
    @Override
    public List parseFormula() {
        List result = new ArrayList<>();
        if(isType()) {
            result.add(getFormula());
            return result;
        }
        List list = splitFormula();
        for(String str : list) {
            if(str.startsWith("#")) {
                String id = str.substring(1);
                CalculatorJsonImpl sub = CalculatorJsonImpl.create(id);
                sub.init();
                result.addAll(sub.parseFormula());
            } else {
                result.add(str);
            }
        }
        return result;
    }
}

在实际项目中可以把子类定义为从数据库获取公式定义,方便管理。

测试数据:

[
  {
    "id": "1",
    "name": "测试1",
    "formula": "1+2",
    "type": false
  },
  {
    "id": "2",
    "name": "测试2",
    "formula": "#1+3",
    "type": false
  },
  {
    "id": "3",
    "name": "测试3",
    "formula": "#2*-1*#4",
    "type": false
  },
  {
    "id": "4",
    "name": "测试4",
    "formula": "5",
    "type": true
  },
  {
    "id": "5",
    "name": "测试5",
    "formula": "2/(3.6+((5-100)+50.3))*(3-1)+6-8",
    "type": false
  }
]

测试类:

package cn.ac.sict.calculator;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        
        Calculator calculator = CalculatorJsonImpl.create("3");
        calculator.init();
        System.out.println(calculator.getName());
        List list = calculator.parseFormula();
        System.out.println("解析后的公式为:" + list);
        String result = Calculator.calculate(list);
        System.out.println("计算结果为:" + result);

        calculator = CalculatorJsonImpl.create("5");
        calculator.init();
        System.out.println(calculator.getName());
        list = calculator.parseFormula();
        System.out.println("解析后的公式为:" + list);
        Calculator.precision = 2;
        result = Calculator.calculate(list);
        System.out.println("计算结果为:" + result);
    }
}

测试结果:

测试3

解析后的公式为:[1, +, 2, +, 3, *, (, 0, -, 1, ), *, 5]
计算结果为:-12

测试5

解析后的公式为:[2, /, (, 3.6, +, (, (, 5, -, 100, ), +, 50.3, ), ), *, (, 3, -, 1, ), +, 6, -, 8]
计算结果为:-2.10

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1005676.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号