自定义表达式计算

直接上干货,前端、后台实现自定义表达式计算
从网络整理而来,经过优化形成

/**
 * 运算相关js
 */

/**计算没有括号的表达式的值(操作符限定为'+'、'-'、'*'、'/') */
function calcExpressionWithoutQuote(expression) {
    if ((expression.indexOf('(') > -1) || (expression.indexOf(')') > -1)) {
        return calcExpression(expression);
    }
    var operators = [];
    var nums = [];
    var lastOperatorIndex = -1;
    for (var i = 0; i < expression.length; i++) {
        var charAtIndex = expression.charAt(i);
        if (isOperatorChar(charAtIndex)) {
            operators[operators.length] = charAtIndex;
            nums[nums.length] = expression.substring(lastOperatorIndex + 1, i);
            lastOperatorIndex = i;
        }
        if (i == (expression.length - 1) && lastOperatorIndex < i) {
            nums[nums.length] = expression.substring(lastOperatorIndex + 1, expression.length);
        }
    }
    if (operators.length <= 0 || nums.length <= 0) {
        return expression;
    }
    // console.info("nums: " + nums + " operators: " + operators);
    while (operators.indexOf('*') > -1 || operators.indexOf('/') > -1) {
        // console.info("nums: " + JSON.stringify(nums) + " operators: " + operators);
        for (var index = 0; index < operators.length;){
            value = operators[index];
            if (value == '*' || value == '/') {
                // console.info("value: " + value + " index: " + index + " num1: " + nums[index] + " num2: " + nums[index + 1]);
                // 拿到操作符位置。
                var tempResult = calcExpressionWithSingleOperator(nums[index], nums[index + 1], value);
                operators.splice(index, 1);
                nums.splice(index, 2, tempResult);
            } else {
                index++;
            }
        }
    }
    var calcResult = nums[0] * 1;
    // 现在只剩下'+'、'-'了
    if (operators.indexOf('+') > -1 || operators.indexOf('-') > -1) {
        for (var index = 0; index < operators.length; index++) {
            var value = operators[index];
            if (value == '+' || value == '-') {
                calcResult = calcExpressionWithSingleOperator(calcResult, nums[index + 1], value);
            }
        }
        return calcResult;
    } else {
        return (nums[0] * 1);
    }
}

/**

 * 计算只有一个操作符的表达式的值(操作符限定为'+'、'-'、'*'、'/')

 */

function calcExpressionWithSingleOperator(num1, num2, operator) {
    if (operator == '+') return calAdd(num1, num2);
    if (operator == '-') return calSub(num1, num2);
    if (operator == '*') return calMulti(num1, num2);
    if (operator == '/') return calDiv(num1, num2);
    return '';
}



/** 计算算术表达式的值 */

function calcExpression(expression) {
    expression = expression.replace(/\s/g, '').replace(/÷/g, '/').replace(/x/g, '*').replace(/×/g, '*').replace(/X/g, '*');
    if (getCharCountInString(expression, '(') != getCharCountInString(expression, ')'))
        return '';
    while (expression && (expression.indexOf('(') > -1) && (expression.indexOf(')') > -1)) {
        // console.info("包含括号:" + expression);
        var firstRightQuoteIndex = expression.indexOf(')');
        var leftQuoteIndex = expression.indexOf('(');
        for (var i = leftQuoteIndex; i < firstRightQuoteIndex; i++) {
            if (expression.charAt(i) == '(') {
                leftQuoteIndex = i;
            }
        }
        var tempExpression = expression.substring(leftQuoteIndex + 1, firstRightQuoteIndex);
        var tempValue = calcExpressionWithoutQuote(tempExpression);
        expression = expression.substring(0, leftQuoteIndex) + tempValue + expression.substring(firstRightQuoteIndex + 1, expression.length);
    }
    // console.info("不含括号:" + expression);
    return calcExpressionWithoutQuote(expression);
}



/**获取字符串中某子字符串出现次数 */

function getCharCountInString(strings, chars) {
    return (strings.split(chars)).length - 1;
}

/**判断字符是否是运算符 */
function isOperatorChar(aimChar) {
    return '+-*/'.indexOf(aimChar) > -1;
}

/**
 * 判断是否所有数字
 * @param val
 * @returns {boolean}
 */
function isNumber(val){
    var regPos = /^\d+(\.\d+)?$/; //非负浮点数
    var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
    if(regPos.test(val) || regNeg.test(val)){
        return true;
    }else{
        return false;
    }
}

/**
 * 加法运算,避免数据相加小数点后产生多位数和计算精度损失。
 *
 * @param num1加数1 | num2加数2
 */
function calAdd(num1, num2) {
    var baseNum, baseNum1, baseNum2;
    try {
        baseNum1 = num1.toString().split(".")[1].length;
    } catch (e) {
        baseNum1 = 0;
    }
    try {
        baseNum2 = num2.toString().split(".")[1].length;
    } catch (e) {
        baseNum2 = 0;
    }
    baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
    return (num1 * baseNum + num2 * baseNum) / baseNum;
};

/**
 * 减法运算,避免数据相加小数点后产生多位数和计算精度损失。
 *
 * @param num1加数1 | num2加数2
 */
function calSub(num1, num2) {
    var baseNum, baseNum1, baseNum2;
    var precision;// 精度
    try {
        baseNum1 = num1.toString().split(".")[1].length;
    } catch (e) {
        baseNum1 = 0;
    }
    try {
        baseNum2 = num2.toString().split(".")[1].length;
    } catch (e) {
        baseNum2 = 0;
    }
    baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
    precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;
    return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
};

/**
 * 乘法运算,避免数据相乘小数点后产生多位数和计算精度损失。
 *
 * @param num1被乘数 | num2乘数
 */
function calMulti(num1, num2) {
    var baseNum = 0;
    try {
        baseNum += num1.toString().split(".")[1].length;
    } catch (e) {
    }
    try {
        baseNum += num2.toString().split(".")[1].length;
    } catch (e) {
    }
    return Number(num1.toString().replace(".", ""))
        * Number(num2.toString().replace(".", ""))
        / Math.pow(10, baseNum);
};
/**
 * 除法运算,避免数据相除小数点后产生多位数和计算精度损失。
 * @param num1被除数 | num2除数
 */
function calDiv(num1, num2) {
    var baseNum1 = 0, baseNum2 = 0;
    var baseNum3, baseNum4;
    try {
        baseNum1 = num1.toString().split(".")[1].length;
    } catch (e) {
        baseNum1 = 0;
    }
    try {
        baseNum2 = num2.toString().split(".")[1].length;
    } catch (e) {
        baseNum2 = 0;
    }
    baseNum3 = Number(num1.toString().replace(".", ""));
    baseNum4 = Number(num2.toString().replace(".", ""));
    // return (baseNum3 / baseNum4) * Math.pow(10, baseNum2 - baseNum1);
    return calMulti((baseNum3 / baseNum4),Math.pow(10, baseNum2 - baseNum1));
};
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CalculateUtil {

	/**
	 * 数字正则
	 */
	private static String numReg = "-?[0-9]+([.][0-9]+)?";

	/**
	 * 匹配一个乘除运算,如1.2*3 1.2/3 1.2*-2 等
	 */
	private static Pattern p1 = Pattern.compile("[0-9]+([.][0-9]+)?[*/]-?[0-9]+([.][0-9]+)?");

    /**
     * 匹配一个加减运算,如1.2+3 1.2-3 1.2--2 1.2+-2等
     */
    private static Pattern p2 = Pattern.compile("-?[0-9]+([.][0-9]+)?[+-][0-9]+([.][0-9]+)?");

	public static BigDecimal bigDecimalCal(BigDecimal a1, BigDecimal a2, char operator) throws Exception {
		switch (operator) {
		case '+':
			return a1.add(a2);
		case '-':
			return a1.subtract(a2);
		case '*':
			return a1.multiply(a2);
		case '/':
			return a1.divide(a2);
		default:
			break;
		}
		throw new Exception("运算符有误!");
	}

	public static String getResult(String str) throws Exception {

		// 处理一下计算过程中出现的--情况,首位--直接去掉,中间--变为+
		str = str.startsWith("--") ? str.substring(2) : str;
		str = str.replaceAll("--", "+");
		str = str.replaceAll("\\+-", "-");
//		System.out.println("新表达式:" + str);

		// 不存在运算符了,即递归结束,这里的正则为匹配所有的正负整数及小数
		if (str.matches(numReg)) {
			return str;
		}

		/* 表示每次递归计算完一步后的表达式 */
		String newExpr = null;
		// 第一步:去括号至无括号
		if (str.contains("(")) {
			/* 最后一个左括号的索引值 */
			int lIndex = str.lastIndexOf("(");
			/* 该左括号对应的右括号的索引 */
			int rIndex = str.indexOf(")", lIndex);
			/* 括号中的字表达式 */
			String subExpr = str.substring(lIndex + 1, rIndex);
//			System.out.println("准备括号:(" + subExpr + ")");
			// 调用本身,计算括号中表达式结果
			newExpr = str.substring(0, lIndex) + getResult(subExpr) + str.substring(rIndex + 1);
			return getResult(newExpr);
		}

		// 第二步:去乘除至无乘除
		if (str.contains("*") || str.contains("/")) {
			Matcher m = p1.matcher(str);
			if (m.find()) {
				/* 第一个乘除表达式 */
				String temp = m.group();
//				System.out.println("计算乘除:" + temp);
				String[] a = temp.split("[*/]");
				newExpr = str.substring(0, m.start())
						+ bigDecimalCal(new BigDecimal(a[0]), new BigDecimal(a[1]), temp.charAt(a[0].length()))
						+ str.substring(m.end());
			}
			return getResult(newExpr);
		}

		// 第三步:去加减至无加减
		if (str.contains("+") || str.contains("-")) {
			Matcher m = p2.matcher(str);
			if (m.find()) {
				/* 第一个加减表达式 */
				String temp = m.group();
//				System.out.println("计算加减:" + temp);
				String[] a = temp.split("\\b[+-]", 2);
				newExpr = str.substring(0, m.start())
						+ bigDecimalCal(new BigDecimal(a[0]), new BigDecimal(a[1]), temp.charAt(a[0].length()))
						+ str.substring(m.end());
			}
			return getResult(newExpr);
		}

		throw new Exception("计算出错!");
	}

	public static void main(String[] args) throws Exception {
		String str = "-2*(-3.5+(-1-1)/2)";
		System.out.println(new BigDecimal(getResult(str)));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值