Garrett J H.
Garrett J H.

Reputation: 23

Extract operators and numbers from an equation using JS

I am working on a jQuery calculator which has a live display which will look like this:

let liveDisplayString = $('#liveDisplay').val();
// ex. '42.5*30.6' or '7/2'

I am trying to separate out the numbers by the operators +, -, * and / and then assign the list items to variables for use in calculation. I also need to grab the operator so I would need another expression to ignore 1-9 and the decimal.

I'm really struggling to understand how to create a regular expression to use in .match().

P.S. I am still very new to programming and the JS language

Upvotes: 1

Views: 938

Answers (2)

Spectric
Spectric

Reputation: 31992

You can use String#split along with regex to get the job done.

The following extracts the operators +, -, * and /.

const value = '42.5*30.6+6-2/6';
const numbers = value.split(/[*]|[+]|[-]|[\/]/);
const operators = value.split(/[^-|+|\/|\*]/).filter(e => e);
console.log(numbers);
console.log(operators);

Upvotes: 2

Kelvin Schoofs
Kelvin Schoofs

Reputation: 8718

Parsing expressions can get quite complicated.

In your case, if an expression is always of the form <value> <operator> <value> (with or without whitespace), you could split by operator:

const OPERATORS = {
    '*': (a, b) => a * b,
    '/': (a, b) => a * b,
    '+': (a, b) => a * b,
    '-': (a, b) => a * b,
};

function evaluate(input) {
    // Loop over the keys, e.g. '*', '/', ...
    for (const operator in OPERATORS) {
        // Split e.g. '1 + 2' into ['1 ', ' 2']
        // but if the operator is '*' and we have '1+2' we get ['1+2']
        const split = input.split(operator);
        if (split.length === 2) {
            // ^ There was exactly one <operator> in the string
            let [a, b] = split;
            // Trim, e.g. "42.5 " into "42.5" then parse as a float
            a = parseFloat(a.trim());
            b = parseFloat(b.trim());
            // Get the arrow function from OPERATORS and return the call result
            return OPERATORS[operator](a, b);
        }
    }
    throw new Error(`Invalid expression!`);
}

console.log(evaluate('42.5 * 30.6'));

If you're new to JS, this might already start to look a bit complicated, and this is just for <value> <operator> <value>. If you actually want to start handling e.g. 5 + 2 * 3 + 3, it's a lot more work.

You could simply parse left-to-right, e.g. [5, '+', 2, '*', 3, '+', 3], but remember the order of operations. You want to evaluate it as (5 + (2 * 3)) + 3 and not as ((5 + 2) * 3) + 3. You'll need to use of an algorithm there to "swap" the binary operations properly. But perhaps that's a topic for much later.


To actually use RegEx for this, that's also an option:

const input = '42.5 * 30.6';

const match = input.match(/^\s*(\d*\.\d+)\s*(\*|\/|\+|\-)\s*(\d*\.\d+)$/);
// Array destructuring, e.g. [0,1,2,3] results in a=1, op=2, b=3
const [, a, op, b] = match;
console.log('a', a);
console.log('op', op);
console.log('b', b);

The RegEx uses \s* everywhere to say "there can be whitespace here, but doesn't need to" while (\d*\.\d+) allows (decimal) numbers, while (\*|\/|\+|\-) wants a operator. We need to escape it with \ because these are all special characters in RegEx.

Upvotes: 1

Related Questions