微信小程序计算算术表达式(代替JS中的eval函数)

1 篇文章 0 订阅
1 篇文章 0 订阅

小程序中计算算术表达式

大家都知道 JS 中的 eval 函数可以直接计算出算术表达式的结果(当然它还有更多的实用策略),但是到了微信小程序,把这个函数给割了,所以,折腾无果后,自己写了个,仅供大家参考。

前情提要:

 - 微信小程序中 eval 函数被割;
 - 网上未找到合适的工具类(尝试用了 rpn.js ,括号嵌套时结果不太满意)。

声明:

 - 本文提及的内容均为原创,难免有不规范或不合理的地方,各位海涵。
 - 文中所述方案,仅以满足自身需求为目的,所以考虑的不是特别全面,后续完善下。
 - 关于JS闭包等操作,此处不涉及,各位看官自行处理;

先说下逻辑:

比如需要计算一个算式是否等于24,这个过程中,算式是字符串拼出来的,是否等于24的关键就是先得出算式的计算结果,比如计算 ‘(13-5)*(9-6)’ :

 - 1、传入算式前,确保算式格式正确(因为计算内部没有做严谨的判断);
 - 2、优先计算括号内的内容(判断括号内的内容,建议从第一个右括号开始,向前查询最近的一个左括号,这样循环下来,即可保证括号优先计算正常);
 - 3、计算加减乘除(去括号后,先计算乘除,后计算加减)。
 - 4、其他语言可以参考此思路,自行处理。

遇到的坑

 本人JS菜鸟,写这个时候爬坑N多,略记一二。
 - 从字符串中提取的数字,做加法计算的时候,需要把字符转成数字,否则会出现‘1’+‘1’ = ‘11’的情况;
 - 修改变量名,一定要及时把所有引用的地方都修改好,否则就没有否则了...
 - 网上的代码,下下来一定要仔细测试,包括我的代码。

上代码

/**
 * By Chice
 * Date:20180316
 * 2206143885@qq.com
 */
/**计算没有括号的表达式的值(操作符限定为'+'、'-'、'*'、'/') */
function calcExpressionWithoutQuote(expression) {

  if ((expression.indexOf('(') > -1) || (expression.indexOf(')') > -1)) {
    return calcQuote(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;
  }
  while (operators.indexOf('*') > -1 || operators.indexOf('/') > -1) {
    operators.forEach(function (value, index) {
      if (value == '*' || value == '/') {
        // 拿到操作符位置。
        var tempResult = calcExpressionWithSingleOperator(nums[index], nums[index + 1], value);
        operators.splice(index, 1);
        nums.splice(index, 2, [tempResult]);
      }
    });
  }

  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 num1 * 1 + num2 * 1;
  if (operator == '-') return num1 * 1 - num2 * 1;
  if (operator == '*') return num1 * num2;
  if (operator == '/') return num1 / num2;
  return NaN;
}

/** 计算算术表达式的值 */
function calcExpression(expression) {
  expression = expression.replace(/\s/g, '').replace(/÷/g, '/').replace(/x/g, '*').replace(/×/g, '*').replace(/X/g, '*');
  if (getCharCountInString(expression, '(') != getCharCountInString(expression, ')'))
    return NaN;
  while (expression && (expression.indexOf('(') > -1) && (expression.indexOf(')') > -1)) {
    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);
  }
  return calcExpressionWithoutQuote(expression);
}

/**获取字符串中某子字符串出现次数 */
function getCharCountInString(strings, chars) {
  return (strings.split(chars)).length - 1;
}
/**判断字符是否是运算符 */
function isOperatorChar(aimChar) {
  return '+-*/'.indexOf(aimChar) > - 1;
}

module.exports = {
  //导出函数,供需求处调用
  calcExpression: calcExpression
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值