直接上干货,前端、后台实现自定义表达式计算
从网络整理而来,经过优化形成
/**
* 运算相关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)));
}
}