v1
2/1/2019 by nikkypizza 2/3/201900
Setup HTML - click to add setup HTML
disable setup JavaScript
Setup JavaScript
const thatString = ' 10   +  33.1 +  2  3 3  *  0 22   %  45   +  10   +  3   2 1 +  2  3 3  +  0 22   -  45    +  10   +  3   2 1 *  22.3  +  0 22   -  45    /  10   +  3   2 1 +  2  3 3  %  0 22   -  45    /  10   +  3   2 1 +  2  3 3  +  0 22   *  45     ';
const thatStringOnlyAddSubstr = ' 10   +  3   2 1 +  2  3 3  +  0 22   -  45   +  10   +  3   2 1 +  2  3 3  +  0 22   -  45    +  10   +  3   2 1 +  2  3 3  +  0 22   -  45    +  10   +  3   2 1 +  2  3 3  +  0 22   -  45    +  10   +  3   2 1 +  2  3 3  +  0 22   -  45     ';

function calcMe(str) {
  const noWsStr = str.replace(/\s/g, '');
  const operators = noWsStr.replace(/[\d.,]/g, '').split('');
  const operands = noWsStr.replace(/[+/%*-]/g, ' ')
                          .replace(/\,/g, '.').split(' ')
                          .map(parseFloat)
                          .filter(it => it);

  if (operators.length >= operands.length){
    throw new Error('Operators qty must me lesser than operands qty')
  };

  while (operators.includes('*')) {
    let opIndex = operators.indexOf('*');
    operands.splice(opIndex, 2, operands[opIndex] * operands[opIndex + 1]);
    operators.splice(opIndex, 1);
  };
  while (operators.includes('/')) {
    let opIndex = operators.indexOf('/');
    operands.splice(opIndex, 2, operands[opIndex] / operands[opIndex + 1]);
    operators.splice(opIndex, 1);
  };
  while (operators.includes('%')) {
    let opIndex = operators.indexOf('%');
    operands.splice(opIndex, 2, operands[opIndex] % operands[opIndex + 1]);
    operators.splice(opIndex, 1);
  };

  let result = operands[0];
  for (let i = 0; i < operators.length; i++) {
    operators[i] === '+' ? (result += operands[i + 1]) : (result -= operands[i + 1])
  }
  return result
}
delete caserun single casemove downdrag and drop case


ready



// Does not support braces
calcMe(thatString)
delete caserun single casemove upmove downdrag and drop case


ready



calcMe(thatStringOnlyAddSubstr)
delete caserun single casemove updrag and drop case


ready



calculate(thatString)
function calculate(input) {

  var f = {
    add: '+',
    sub: '-',
    div: '/',
    mlt: '*',
    mod: '%',
    exp: '^'
  };

  // Create array for Order of Operation and precedence
  f.ooo = [
    [
      [f.mlt],
      [f.div],
      [f.mod],
      [f.exp]
    ],
    [
      [f.add],
      [f.sub]
    ]
  ];

  input = input.replace(/[^0-9%^*\/()\-+.]/g, ''); // clean up unnecessary characters

  var output;
  for (var i = 0, n = f.ooo.length; i < n; i++) {

    // Regular Expression to look for operators between floating numbers or integers
    var re = new RegExp('(\\d+\\.?\\d*)([\\' + f.ooo[i].join('\\') + '])(\\d+\\.?\\d*)');
    re.lastIndex = 0; // take precautions and reset re starting pos

    // Loop while there is still calculation for level of precedence
    while (re.test(input)) {
      output = _calculate(RegExp.$1, RegExp.$2, RegExp.$3);
      if (isNaN(output) || !isFinite(output)) 
        return output; // exit early if not a number
      input = input.replace(re, output);
    }
  }

  return output;

  function _calculate(a, op, b) {
    a = a * 1;
    b = b * 1;
    switch (op) {
      case f.add:
        return a + b;
        break;
      case f.sub:
        return a - b;
        break;
      case f.div:
        return a / b;
        break;
      case f.mlt:
        return a * b;
        break;
      case f.mod:
        return a % b;
        break;
      case f.exp:
        return Math.pow(a, b);
        break;
      default:
        null;
    }
  }
}

//------ALSO

//1) not so safe (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
//function evil(fn) {
  //return new Function('return ' + fn.replace(/\s/g,''))();
//}
//evil(thatString)

// 2) totally not safe
//     eval('10   +  3 %  21 +  2 * 330 *2/2   -  45')
Test Case - click to add another test case
Teardown JS - click to add teardown JavaScript
Output (DOM) - click to monitor output (DOM) while test is running
RUN