Evaluate mathematical expression
Instructions
Given a mathematical expression as a string you must return the result as a number.
Numbers
Number may be both whole numbers and/or decimal numbers. The same goes for the returned result.
Operators
You need to support the following mathematical operators:
- Multiplication
*
- Division
/
(as floating point division) - Addition
+
- Subtraction
-
Operators are always evaluated from left-to-right, and *
and /
must be evaluated before +
and -
.
Parentheses
You need to support multiple levels of nested parentheses, ex. (2 / (2 + 3.33) * 4) - -6
Whitespace
There may or may not be whitespace between numbers and operators.
An addition to this rule is that the minus sign (-
) used for negating numbers and parentheses will never be separated by whitespace. I.e all of the following are valid expressions.
1-1 // 0
1 -1 // 0
1- 1 // 0
1 - 1 // 0
1- -1 // 2
1 - -1 // 2
1--1 // 2
6 + -(4) // 2
6 + -( -4) // 10
And the following are invalid expressions:
1 - - 1 // Invalid
1- - 1 // Invalid
6 + - (4) // Invalid
6 + -(- 4) // Invalid
Validation
You do not need to worry about validation - you will only receive valid mathematical expressions following the above rules.
Restricted APIs
NOTE: Both eval
and Function
are disabled.
JavaScript
function splitSubtractionSequence(expr) {
const result = [];
let current = "";
for (let i = 0; i < expr.length; i++) {
const char = expr[i];
if (char === "-") {
result.push(current);
current = "";
}
current += char;
}
result.push(current);
return result.filter((item) => Boolean(item));
}
function evalExpressionGroup(expr) {
// Remove all spaces from the expression
expr = expr.replace(/\s+/g, "");
// Convert all double negatives to a positive
expr = expr.replace(/--/g, "+");
// Handle strings of subtraction without executing them
let numbers = expr.split(/[^0-9\-\.]/);
numbers = numbers.map((item) => splitSubtractionSequence(item));
numbers = numbers.reduce((acc, val) => acc.concat(val), []);
return expr;
};
function calc(expr) {
// Capture all parenthesis groups for proper order of operations
const groups = expr.match(/\(.*\)/g) || [];
// Evaluate each set of parenthesis
for (let i = 0; i < groups.length; i++) {
const parenthesis = groups[i].slice(1, -1);
const output = evalExpressionGroup(parenthesis);
expr = expr.replace(groups[i], output);
}
// Evaluate and return the simplified expression
return evalExpressionGroup(expr);
};