支持加减乘除和四则运算

测试类:

package com.enter.swing;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.TreeMap;

public class Test12 {
	
	
	
	public static void main(String[] args) {
		Test12 test=new Test12();
		ArrayList<String> formulals=new ArrayList<>();//计算公式集合
		formulals.add("金额=数量*单价*(1+1)");
		ArrayList Caldatas=new ArrayList<>();//计算数据集合
		ArrayList als=new ArrayList<>();//第一组计算集合
		als.add(10);//数量
		als.add(5);//单价
		als.add(0);//金额
		Caldatas.add(als);//添加到计算数据集合
		ArrayList als1=new ArrayList<>();//第二组计算集合
		als1.add(5);//数量
		als1.add(5);//单价
		als1.add(0);//金额
		Caldatas.add(als1);//添加到计算数据集合
		ArrayList<String> colnumCals=new ArrayList<>();//计算数据的列名
		colnumCals.add("数量");
		colnumCals.add("单价");
		colnumCals.add("金额");
		ArrayList calformula = test.Calformula(formulals, Caldatas, colnumCals);
		System.out.println(calformula);
	}
	
	
	/**
	 * 自定义公式计算
	 * @param formulals 计算公式集合
	 * @param Caldatas 计算数据集合
	 * @param colnumCals 列名集合
	 * @return
	 */
	private ArrayList Calformula(ArrayList<String> formulals,ArrayList Caldatas,ArrayList<String> colnumCals){
		if(formulals==null||formulals.size()==0){
			return Caldatas;
		}
		ArrayList als=new ArrayList<>();
		char[] cArray ={'+','-','*','/','(',')','[',']','{','}','='};//定义运算符
  		Map<String,String> formulamap=new HashMap<>();
  		Map<String, String> sortMap = new TreeMap<>();
  		for (int i1 = 0; i1 < formulals.size(); i1++) {
  			String fkey="";//键:结果
				String fvalue="";//值:公式
			String[] formulasplit = formulals.get(i1).split("=");
			if(formulasplit.length==2){
				for (int j1 = 0; j1 < formulasplit.length; j1++) {
    				boolean validationformula = Validationformula(formulasplit[j1]);//检查是否有运算符
    				if(validationformula){
    					fvalue=formulasplit[j1];
    				}else{
    					fkey=formulasplit[j1];
    					sortMap.put(i1+"", fkey);
    				}
    			}
			}else{
				continue;
			}
			formulamap.put(fkey, fvalue);
		}
  		Map<String,Integer> formulaCellmap=new HashMap<>();//用来储存列名称和列下标
			for (int i1 = 0; i1 < formulals.size(); i1++) {
				String str=formulals.get(i1);
				String rs="";
				char[] charArray = str.toCharArray();
    			for (int j1 = 0; j1 < charArray.length; j1++) {
    				for (int k = 0; k < cArray.length; k++) {
    					if(charArray[j1]==cArray[k]){
    						charArray[j1]=',';
    					}
    				}
    				if(!(charArray[j1]=='.')){
    	            	if (charArray[j1] < '0' || charArray[j1] > '9') {
    	                    rs+=charArray[j1];
    	                }
    	            }
    			}
				String[] split = rs.split(",");
				for (int j = 0; j < split.length; j++) {
    				for (int i = 0; i < colnumCals.size(); i++) {
  		  				String col = colnumCals.get(i);
        				if(col!=null&&!col.equals("")&&col.trim().equals(split[j].trim())){
			  				formulaCellmap.put(col, i);
			  			}
    				}
				}
			}
      	Map<Integer,String> mapCal=null;
      	Map<String,String> fmap=null;
      	for (int j = 0; j < Caldatas.size(); j++) {
      		ArrayList Caldata=(ArrayList)Caldatas.get(j);
      		mapCal=new HashMap<>();
      		fmap=new HashMap<>();
      		for (int i = 0; i < Caldata.size(); i++) {
          		for (Entry<String, Integer> entry : formulaCellmap.entrySet()) {
          			String key = entry.getKey();
          			Integer value = entry.getValue();
          			if(value==i){
          				fmap.put(key,Caldata.get(i)==null?"":Caldata.get(i).toString().trim());
          			}
          		}
        		if(i==Caldata.size()-1){
        			for (Entry<String, String> entry : sortMap.entrySet()) {//这里遍历的是排序map,所以mapKey是value,mapValue是根据mapKey从formulamap中拿的
    			        String mapKey = entry.getValue();//计算结果名称
    			        String mapValue = formulamap.get(entry.getValue());//计算公式
    			        String str=mapValue;
            			String rs="";
            			char[] charArray = str.toCharArray();
            			for (int j1 = 0; j1 < charArray.length; j1++) {
            				for (int k = 0; k < cArray.length; k++) {
            					if(charArray[j1]==cArray[k]){
            						charArray[j1]=',';
            					}
            				}
            				if(!(charArray[j1]=='.')){
            	            	if (charArray[j1] < '0' || charArray[j1] > '9') {
            	                    rs+=charArray[j1];
            	                }
            	            }
            			}
            			String[] split = rs.split(",");
            			for (int k = 0; k < split.length; k++) {
            				for (Map.Entry<String, String> entry1 : fmap.entrySet()) {
            			        String mapKey1 = entry1.getKey();
            			        String mapValue1 = entry1.getValue();
            			        if(split[k]!=null&&!split[k].equals("")&&split[k].trim().equals(mapKey1.trim())){
            			        	str = str.replace(split[k], mapValue1);
            					}
            			    }
            			}
            			boolean b1=false;
            			char[] charArr=str.toCharArray();
            			for (int k = 0; k < charArr.length; k++) {
            				boolean b=false;
            				for (int k2 = 0; k2 < cArray.length; k2++) {
            					if(charArr[k]==cArray[k2]){
            						b=true;
            						break;
            					}else {
            						b=false;
            					}
            				}
            				if(b){
            					b1=true;
            				}else{
            					if(charArr[k]=='.'){
            						b1=true;
            					}else if(!(charArr[k]<'0')&&!(charArr[k]>'9')){
            						b1=true;
            					}else{
            						b1=false;
            						break;
            					}
            				}
            			}
            			if(b1){
            				String calValue=cal(charArr)[0];//计算结果
                			if(formulaCellmap.get(mapKey)!=null&&!calValue.equals("N")){
                				mapCal.put(formulaCellmap.get(mapKey), calValue);
                				fmap.put(mapKey, calValue);//将计算结果放入存放计算列和对应值的map,可能下个算式会用到
                			}
            			}
    			    }
        		}
			}
      		List tmpList=new ArrayList<>();
        	for (int k = 0; k < Caldata.size(); k++) {
        		String tvalue="";
        		boolean b=false;
        		for (Entry<Integer, String> entry : mapCal.entrySet()) {
        			int  mapKey = entry.getKey();
			        String mapValue = entry.getValue();
			        if(k==mapKey){
			        	b=true;
			        	tvalue=mapValue;
			        }
			    }
        		if(b){
        			tmpList.add(tvalue);
        		}else{
        			tmpList.add(Caldata.get(k));
        		}
			}
        	als.add(tmpList) ;		
    	}
		return als;
	}
	
	/**
     * 计算的主要实现方法
     */
    public static String[] cal(char[] charArr) {
        String sum = "0"; // 和
        int len = charArr.length;
        Stack<String> stack = new Stack<>(); // 栈
        int i = 0; // 因为要利用i来计算以此递归处理了多少个字符,所以放到外面来定义
        try {
        	 for (; i < charArr.length; i++) {
				// result记录两个数据,result[0]是本次递归处理的数的和。result[1]是本次递归处理了多少个字符
             	String[] result;
                 if (charArr[i] == ')' || charArr[i] == ']' || charArr[i] == '}') { // 遇到右括号说明本次递归结束
                     break;
                 } else if (charArr[i] == '(' || charArr[i] == '[' || charArr[i] == '{') {//遇到左括号就进入新的递归
				 	// 递归,入参是当前字符+1到末尾。因为并不知道右括号在什么位置,所以直接取到末尾
                     result = cal(Arrays.copyOfRange(charArr, i + 1, len));
                     stack.push(result[0]);// 讲一组括号内计算的值入栈
                     i += Integer.parseInt(result[1]); // 递归是处理了一批字符的,所以下次处理是当前位置加上递归处理的字符长度,继续处理
                 } else if (charArr[i] >= '0' && charArr[i] <= '9') { //遇到数字的处理
                     // 因为字符数组存储的是单个数字,而真正的数字肯定有好几位数,所以需要讲连续的几个数字字符合并成一个整数
                     result = findNum(i, charArr);
                     stack.push(result[0]); //取到数字先入栈
                     i += Integer.parseInt(result[1]) - 1;
                 } else {
                     // 获取运算符后面的数
                     result = findNum(i + 1, charArr);
                     int tempI=i; // 后面的i可能会变动,所以要记录下当前值
                     if (Integer.parseInt(result[1]) == 0) { // 若寻找数字时一个字符都没运算,则可以确定后面后面跟的是括号
                         i++; //跳过括号
                         result = cal(Arrays.copyOfRange(charArr, i + 1, len));//是括号则递归求值
                     }
                     if (charArr[tempI] == '*') {
                         String number1 = stack.pop(); // 遇到乘除要先出栈,与后面的数字计算完再次入栈,因为栈中只存储加法运算
                         String number2 = result[0];
                         stack.push(String.valueOf(mul(number1, number2)));// 计算完在入栈
                     } else if (charArr[tempI] == '/') {
                         String number1 = stack.pop();
                         String number2 = result[0];
                         stack.push(String.valueOf(div(number1, number2)));
                     } else if (charArr[tempI] == '-') {
                         stack.push("-"+result[0]); // 减法相当于加负数
                     } else if (charArr[tempI] == '+') {
                         stack.push(result[0]);
                     }
                     i += Integer.parseInt(result[1]); // 确定当前运算到什么位置了
                 }
             }
             //将栈中数字求和
             while (!stack.empty()) {
                 //sum += Integer.parseInt(stack.pop());
             	sum=String.valueOf(add(sum, stack.pop()));
             }
		} catch (Exception e) {
			// TODO: handle exception
			return new String[]{"N"};
		}
        return new String[]{sum,i+1+""};// 第一个数是当前栈中的和,第二个数字是本次递归处理的字符数
    }
    /**
     * 整合连续几个字符数字为一个完整的整数
     */
    public static String[] findNum(int index, char[] charArr) {
        int i = index;
        int fuHaoWei = 1; // 可能会遇到负数,所以最终要乘以符号位,默认为1,即正整数
        // 判断是否为负数
        if (charArr[i] == '-') {
            fuHaoWei *= -1; //若为负数则符号位=-1
            i++; // 此时处理了一个“-”,也要记得加1
        }
        // 计算连续数字的长度,找到这个范围
        for (; i < charArr.length; i++) {
            // 当遇到超出数字字符范围的字符,即连续数字结束
            if(!(charArr[i]=='.')){
            	if (charArr[i] < '0' || charArr[i] > '9') {
                    break;
                }
            }
        }
        if (fuHaoWei == -1) {
            //输出还是上面那个result数组。负数因为多了个“-”开头,所以index + 1
            return new String[]{"-"+pinShuzi(Arrays.copyOfRange(charArr, index + 1, i)),( i - index)+""};
        } else {
            return new String[]{(pinShuzi(Arrays.copyOfRange(charArr, index, i)))+"", (i - index)+""};
        }
    }
    /**
     * 
     * 将连续数字拼接成一个真正的整数,这里用位运算可能更优雅
     */
    public static String pinShuzi(char[] charArr) {
        String sum = "";
        for (int i = 0; i <charArr.length; i++) {
            sum += String.valueOf(charArr[i]);
        }
        return sum;
    }
	
	@SuppressWarnings("unused")
	public static boolean Validationformula(String param){
		boolean b=true;
		if(param.indexOf("+")!=-1){
				b=false;
			}else if(param.indexOf("-")!=-1){
				b=false;
			}else if(param.indexOf("*")!=-1){
				b=false;
			}else if(param.indexOf("/")!=-1){
				b=false;
			}else if(param.indexOf("(")!=-1){
				b=false;
			}else if(param.indexOf(")")!=-1){
				b=false;
			}else if(param.indexOf("[")!=-1){
				b=false;
			}else if(param.indexOf("]")!=-1){
				b=false;
			}else if(param.indexOf("{")!=-1){
				b=false;
			}else if(param.indexOf("}")!=-1){
				b=false;
			}
		return !b;
	}
	/**
	 * 公式计算
	 * @param Formulals公式
	 * @param params参数
	 * @return
	 */
	private String Formularesults(String formula){
		
		return null;
	}
	
	// 默认除法运算精度
    private static final int DEF_DIV_SCALE = 16;


    /**
     * 加法
     * @param v1
     * @param v2
     * @return
     */
    public static double add(String v1, String v2) {
        java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.add(b2).doubleValue();
    }


    /**
     * 减法
     * @param v1
     * @param v2
     * @return
     */
    public static double sub(String v1, String v2) {
        java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.subtract(b2).doubleValue();
    }


    /**
     * 乘法
     * @param v1
     * @param v2
     * @return
     */
    public static double mul(String v1, String v2) {
        java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.multiply(b2).doubleValue();
    }


    /**
     * 除法
     * @param v1
     * @param v2
     * @return
     */
    public static double div(String v1, String v2) {
        java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
    }
}

输出结果:

java自定义公式计算 jexl java自定义公式计算_java自定义公式计算 jexl