使用Javascript或jQuery评估字符串表达式

时间:2014-11-14 00:06:06

标签: javascript jquery

我必须评估下面的表达式,这些表达式在字符串变量中可用,而不使用eval或外部库或第三方软件包:

"abs(add(multiply(-1,multiply(-1,subtract(89,19880))),subtract(add(12,add(247,45986)),98)))"

有人可以建议如何使用Javascript或jQuery完成它吗?

  • add(expr1,expr2) - 接受两个操作数并返回它们的总和。
  • subtract(expr1,expr2) - 接受两个操作数并返回它们的差值(expr1 - expr2)。
  • multiply(expr1,expr2) - 接受两个操作数并返回其产品。
  • abs(expr1) - 接受一个操作数并返回其绝对值。

4 个答案:

答案 0 :(得分:0)

使用堆栈实现传统的表达式评估方法 - 操作数堆栈,运算符堆栈。从堆栈推送弹出。这是我能想到的最佳方式。

答案 1 :(得分:0)

我并没有真正打扰使代码高效或防弹(这里可能存在一些错误),但这里有一个关于如何做到这一点的例子。您可以将中缀表达式转换为后缀表示形式作为标记数组,然后执行该后缀表示的计算。

注意:我不允许对带有空格的表达式进行正确的标记,但如果不是您需要的话,您可以更改它。

var logEl = document.getElementById('log'),
    expInput = document.querySelector('input');

document.querySelector('button').addEventListener('click', function () {
  updateEvaluationResult(expInput.value);
});

updateEvaluationResult(expInput.value);

function updateEvaluationResult(exp) {
  var logMsg;
  try { logMsg = evaluateExpression(exp); }
  catch (e) {
    logMsg = e.message + ('charIndex' in e? ' (char index ' + e.charIndex + ')' : '')
  }
  
  logEl.textContent = logMsg;
  
}


function evaluateExpression(exp) {
  var functions = {
    abs: Math.abs,
    multiply: function(num1, num2) {
      return num1 * num2;
    },
    substract: function(num1, num2) {
      return num1 - num2;
    },
    add: function(num1, num2) {
      return num1 + num2;
    }
  };

  return (evaluateExpression = function(exp) {
    var fn;

    return postfixTokenizationOf(exp).reduce(function(resultStack, token) {
      if (typeof token == 'number') resultStack.push(token);
      else {
        fn = functions[token];
        if (!fn) throw new Error("'" + token + "' is an invalid function");
        resultStack.push(functions[token].apply(
          null, 
          resultStack.splice(resultStack.length - fn.length)
        ));
      }

      return resultStack;
    }, []).pop();
  })(exp);
}

function postfixTokenizationOf(exp) {

  if (!exp) return [];

  var stack = [],
    output = [],
    indexOf = [].indexOf,
    tokenRx = /[^-(),\d]+|[(),]|[-\d]+/g,
    functionTokenRx = /[^-(),\d]+/,
    charTokenHandlers = {
      '(': stack.push.bind(stack, '('),
      ')': handleRightParenthesis,
      ',': handleArgSeperator
    },
    charTokenHandler, token, match;

  while (match = tokenRx.exec(exp)) {
    token = match[0];

    if ((charTokenHandler = charTokenHandlers[token])) {
      charTokenHandler();
      continue;
    }

    if (isNumeric(token)) {
      output.push(+token);
      continue;
    }

    handleFunction();
  }

  if (popStackUntilOneOfTokenFound('()')) throwMismatchedParenthesisError();

  return output;

  function handleFunction() {
    var nextCharIndex = tokenRx.lastIndex;

    if (exp[nextCharIndex] != '(') throwError('expected a function call');
    else stack.push(token);
  }

  function handleRightParenthesis() {
    if (!popStackUntilOneOfTokenFound('(')) throwMismatchedParenthesisError();
    stack.pop();
    if (isFunction(topOfStack())) output.push(stack.pop());
  }

  function handleArgSeperator() {
    if (!popStackUntilOneOfTokenFound('(')) throwError(
      'mismatched parenthesis or misplaced argument seperator'
    );
  }

  function popStackUntilOneOfTokenFound(tokenChars) {
    var t;

    while (indexOf.call(tokenChars, t = topOfStack()) == -1 && t) output.push(stack.pop());

    return !!stack.length;
  }

  function throwError(msg) {
    var err = new Error(msg);
    err.charIndex = tokenRx.lastIndex;
    throw err;
  }

  function throwMismatchedParenthesisError() {
    throwError('mismatched parenthesis');
  }

  function topOfStack() {
    return stack[stack.length - 1];
  }

  function isFunction(token) {
    return functionTokenRx.test(token);
  }

  function isNumeric(token) {
    return parseFloat(token) == token;
  }
}
input {
  width: 500px;
}
<label>Exp:
  <input type="text" value="abs(add(multiply(-1,multiply(-1,substract(89,19880))),substract(add(12,add(247,45986)),98)))">
</label>

<div id="log"></div>

<button>Evaluate</button>

答案 2 :(得分:-1)

最简单的方法是创建一堆能够满足您需求的函数,然后eval()代码。

function calc(str){
  function subtract(a, b){
    return a-b;
  }
  function add(a, b){
    return a+b;
  }
  function mulitiply(a, b){
    return a*b;
  }
  function divide(a, b){
    return a/b;
  }
  function abs(a){
    return Math.abs(a);
  }
  return eval('('+str+')');
}
console.log(calc('abs(add(multiply(-1,multiply(-1,subtract(89,19880))),subtract(add(12,add(247,45986)),98)))'));

答案 3 :(得分:-1)

如何编写自定义函数?

 function add(ad1, ad2) {
     var sum = parseFloat(ad1) + parseFloat(ad2);
     return sum;
 }

 function subtract(sub1, sub2) {
     var sub = parseFloat(sub1) - parseFloat(sub2);
     return sub;
 }

 function multiply(mlt1, mlt2) {
     var mlt = parseFloat(mlt1) * parseFloat(mlt2);
     return mlt;
 }

 function abs(ab1) {
     var abs = Math.abs(parseFloat(ab1));
     return abs;
 }

 function evaluatethis(exp) {
     document.write('<script>alert(' + exp + ');</' + 'script>');
 }
 evaluatethis("abs(add(multiply(-1,multiply(-1,subtract(89,19880))),subtract(add(12,add(247,45986)),98)))");