0

Just say I have a string like this: '1 + 2 + 3 * 4'

Is it possible to calculate it from left to right (sequentially? Linearly?) so that it equals 24 and not 15 ?

I don't know what the string is before-hand, so it might be '1 + 2' or it might be '1 + 7 * 11 - 18 / 32 * 155'

danwellman
  • 9,068
  • 8
  • 60
  • 88
  • 3
    ..why no parenthesis? `(1 + 2 + 3) * 4` – Paul S. Apr 27 '13 at 09:47
  • Well, that was the first thing I thought of course, but, how to put them in the correct place? What if it's the second string example and I need more than 1 set of parentheses? – danwellman Apr 27 '13 at 09:51
  • Check parsing trees: http://stackoverflow.com/questions/2705727/generate-syntax-tree-for-simple-math-operations – Dragos Bobolea Apr 27 '13 at 09:51

3 Answers3

1

Assuming you start with a number and spaces only (and always) occur between numbers and operators, you could split the string and pass it through an object of defined operators

var num_eval = (function () {
    var ops = {
        '+': function (x, y) {return x + y},
        '-': function (x, y) {return x - y},
        '*': function (x, y) {return x * y},
        '/': function (x, y) {return x / y}
        // etc..
    };
    return function (str_command) {
            var str_arr = str_command.split(' '),
                lhs = +str_arr[0], i = 1; // + to cast Number
            for (; i < str_arr.length; i = i + 2) {
                lhs = ops[str_arr[i]](lhs, +str_arr[i+1]); // + to cast Number
            }
            return lhs;
        };
    }());

num_eval('1 + 2 + 3 * 4'); // 24
num_eval('1 + 7 * 11 - 18 / 32 * 155'); // 339.0625

If you want to be a little more relaxed about string formatting, then you could use the following RegExp.

str_arr = str_command.match(/([\+\-\*\/]|[\d]*[\.e]?[\d]+)/g)

The loop still assumes an odd length array, starting with a Number (as String).

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • To relax it a bit, you could use _RegExp_ instead of `.split`, e.g. `/([\+\-\*\/]|[\d]*\.?[\d]+)/g` – Paul S. Apr 27 '13 at 10:03
  • Well, I'm already using regex to trim off any trailing operators, but thanks. Still implementing this... – danwellman Apr 27 '13 at 10:04
  • Oh, if you're using `-` as "negative" and not "subtract", the regex I posted won't always work, but other than that it should be fine. – Paul S. Apr 27 '13 at 10:10
1

A one-liner:

result = str.match(/\D*\d+/g).reduce(function(r, e) { return eval(r + e) })
georg
  • 211,518
  • 52
  • 313
  • 390
  • This looks very, very promising, however, I've not been able to integrate with my exiting (and necessary) code. Definitely will be looking into this further, thanks :) – danwellman Apr 27 '13 at 11:18
0

Usually you just insert parenthesis.

But if by some reason you cannot do that, you can split the string by operators and then evaluate previous_part + next_part for each of them.

Here's a super simple example:

var string_to_calculate = '1 + 2 + 3 * 4'
var parts = string_to_calculate.split(' ');
var result = parts[0];

for (var i = 1; i < parts.length - 1; i += 2) {
    result = eval(result + parts[i] + parts[i + 1]);
}

alert(result);
Darko Kenda
  • 4,781
  • 1
  • 28
  • 31