JavaScript — write a function that can solve a math [removed]without eval)

后端 未结 2 1066
礼貌的吻别
礼貌的吻别 2020-12-21 06:45

Ultimately I want to take this:

2x + 3 = 5

and solve for x, by first subtract 3 from both sides so 2x = 2, then divide both si

2条回答
  •  别那么骄傲
    2020-12-21 07:15

    While your problem doesn't require to construct, binary expression tree is a good way to brainstorm the logic to solve a math query.

    So for the query 3 - 6 * 3 / 9 + 5, the representative binary expression tree is:

    plus
      |_minus
      | |_3
      | |_divide
      |   |_times
      |   | |_3
      |   | |_6
      |   |_9
      |_5
    

    to solve above tree, you recursively solve from the leaf level up to the root.

    Again, you don't need to construct a tree. It just helps us to see the logic of parsing here:

    • Get the last minus or plus expression in query and solve left and right child of that expression.
    • If no plus/minus, get the last times/division expression and solve left and right child
    • If meet a number, return that number value.

    Given above logic, here is an implementation:

    function solve(str) {
      var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
      if (expressionIndex === -1) {
        expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
      }
      if (expressionIndex === -1) {
        var num = Number.parseInt(str.trim());
        if (isNaN(num)) {
          throw Exception("not a valid number");
        } else {
          return num;
        }
      } else {
        var leftVal = solve(str.substring(0, expressionIndex).trim());
        var rightVal = solve(str.substring(expressionIndex + 1).trim());
        switch (str[expressionIndex]) {
          case "+":
            return leftVal + rightVal;
          case "-":
            return leftVal - rightVal;
          case "*":
            return leftVal * rightVal;
          case "/":
            return leftVal / rightVal;
        }
      }
    }
    
    function parse(str) {
      var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
      if (expressionIndex === -1) {
        expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
      }
      if (expressionIndex === -1) {
        var num = Number.parseInt(str.trim());
        if (isNaN(num)) {
          throw Exception("not a valid number");
        } else {
          return { type: "number", value: num };
        }
      } else {
        var leftNode = parse(str.substring(0, expressionIndex).trim());
        var rightNode = parse(str.substring(expressionIndex + 1).trim());
        return {
          type: "expression",
          value: str[expressionIndex],
          left: leftNode,
          right: rightNode
        };
      }
    }
    
    console.log(solve("3 - 6 * 3 / 9 + 5"));
    console.log(parse("3 - 6 * 3 / 9 + 5"));

    Above is a solution for very simple query with only +, -, *, / (no parenthesis, e.g.). For solving a equation like your first example requires a lot more of work.

    EDIT: add a parse function to return the tree.

提交回复
热议问题