0

A user inputs a math problem and the problem answers it. My code works for all 1 part problems such as "1+1" and "4*5". But after that it skips the last part of the problem. for example "1+1+1" outputs 2 and "1+1+1+1" outputs 3 and "4*5-6" outputs 20. What am I doing wrong here? I feel like it's simple but I tried a few things.

Relevant code:

function scan(i) {
    "use strict";
    var num,
    schar = "",
    strnum = "",
    scanarray = [];
    for (i; i <= input.length; i++ ) {
        schar = input.charAt(i);
        if (isoperator(schar)) {
        break;
        }
        strnum = strnum + schar;
    } 
    if (strnum !== "") { num = Number(strnum); }
    scanarray[0] = schar;
    scanarray[1] = i;
    scanarray[2] = num;
    return scanarray;
}

for (i; i <= input.length; i) {
    scanarray = scan(i + 1);
    schar = scanarray[0];
    i = scanarray[1];
    num = scanarray[2];
    if (schar1 !== "") {
        switch(schar1)
        {
            case "+":
                answer = num1 + num;
                break;
            case "-":
                answer = num1 - num;
                break;
            case "*":
                answer = num1 * num;
                break;
            case "/":
            case "÷":
                answer = num1 / num;
                break;
        }
        schar1 = "";
    } else {
        switch(schar)
        {
            case "+":
                answer = answer + num;
                break;
            case "-":
                answer = answer - num;
                break;
            case "*":
                answer = answer * num;
                break;
            case "/":
            case "÷":
                answer = answer / num;
                break;
        }
    }
}

I tried changing the for loop in the scan function to go until "i <= input.length + 1" and the for loop in the calculate function to the same and i tried changing both, but none of that worked. Any help is greatly appreciated!

Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144

2 Answers2

0

Here is a very naive re-implementation of your code that should at least set you on your way toward a more idiomatically Javascript way of achieving your aim, rather than the comparatively un-readable C-like methodology for stepping through each character of input. I suppose it could be argued the various regular expressions are also hard to read, but they make up for that in concision, which in turn lends itself toward maintainability, and I would argue the reason your code doesn't work the way you expect is a maintainability issue.

console.log(" 44 * 5 - 6 / 2 + 4 =", performMath(" 44 * 5 - 6 / 2 + 4")); 
console.log("4*5-2 =", performMath("4*5-2")); 


function performMath(input) {
  var output, operands, operators;

  input = input.replace(/\s+/g, '');

  if (input.match(/\d+([\*-]\d+)*/g)) {
    operands = input.split(/[-\*\/\+]/);
    operators = input.split(/\d+/).filter(function(i) {
      return i
    });

    for (var i = 0, n = operators.length; i < n; i++) {
      output = output || operands[0];
      eval("output=output" + operators[i] + operands[i + 1]);
    }
  }

  return output;
}
Adriano P
  • 2,045
  • 1
  • 22
  • 32
Dexygen
  • 12,287
  • 13
  • 80
  • 147
  • It should be noted that "set you on your way" will involve following the usual order of operations (you should get 221, not 111). I'm not experienced enough with Javascript to comment on the use of `eval`. It's usually considered evil, but perhaps not in this case? – Teepeemm Jan 22 '14 at 04:33
  • 2
    Looking at this two years later, it just occurred to me. If you're going to use eval at all, why not just use eval and nothing else? `performMath=eval` would follow the correct order of operations. You could use a regex to sanitize the input first, if you wanted. If you wanted to remove the eval, you could just switch on that character. – Teepeemm Jun 03 '16 at 15:48
  • @Teepeemm Have you seen this clever way of summing up all numbers in an array? http://stackoverflow.com/a/15946541/34806 – Dexygen Jun 03 '16 at 16:52
0

Here's an approach that avoids using eval, and correctly follows the order of operations. The trick is to first take care of multiplication and division (left to right) and then deal with addition and subtraction (left to right). If you want to get much fancier, then you might want to look into algorithms such as the Shunting Yard Algorithm.

console.log(" 44 * 5 - 6 / 2 + 4 =", performMath(" 44 * 5 - 6 / 2 + 4")); 
console.log("4*5-2 =", performMath("4*5-2")); 

function performMath(input) {
  input = input.replace(/\s+/g,'');
  input = input.replace(/\d+[*/]\d+/g,performMult);
  while ( /[+-]/.test(input) ) {
    input = input.replace(/^(\d+)([+-])(\d+)/,oneOper);
  }
  return input;
}
function performMult(input) {
  while ( /[*/]/.test(input) ) {
    input = input.replace(/^(\d+)([*/])(\d+)/,oneOper);
  }
  return input;
}
function oneOper(m,p1,p2,p3) {
  switch (p2) {
  case '+': return +p1 + +p3;
  case '-': return +p1 - +p3;
  case '*': return +p1 * +p3;
  case '/': return +p1 / +p3;
  }
}
Teepeemm
  • 4,331
  • 5
  • 35
  • 58