function evaluateExpression(expression) {
try {
// Use eval() for simplicity, but be cautious in production environments.
// Consider using a dedicated expression parser for better security and error handling.
const result = eval(expression);
if (isNaN(result) || !isFinite(result)) {
return "Invalid expression"; // Handle cases like division by zero or invalid input
}
return result;
} catch (error) {
return "Invalid expression"; // Handle syntax errors
}
}
// Examples:
console.log(evaluateExpression("10 + 5 * 2 - 3 / 3")); // Output: 19
console.log(evaluateExpression("2 * (5 + 3)")); // Output: 16
console.log(evaluateExpression("10 / 0")); // Output: Invalid expression
console.log(evaluateExpression("1 + a")); // Output: Invalid expression
// More robust solution using a simple recursive descent parser (handles +, -, *, /, parentheses):
function evaluateExpressionRobust(expression) {
let index = 0;
function peek() {
return expression[index];
}
function consume(char) {
if (peek() !== char) {
throw new Error("Unexpected character: " + peek());
}
index++;
}
function parseNumber() {
let numStr = "";
while (index < expression.length && (/\d|\./).test(peek())) {
numStr += peek();
index++;
}
return parseFloat(numStr);
}
function parseFactor() {
if (peek() === '(') {
consume('(');
const result = parseExpression();
consume(')');
return result;
} else {
return parseNumber();
}
}
function parseTerm() {
let left = parseFactor();
while (peek() === '*' || peek() === '/') {
const operator = peek();
consume(operator);
const right = parseFactor();
if (operator === '*') {
left *= right;
} else {
left /= right;
}
}
return left;
}
function parseExpression() {
let left = parseTerm();
while (peek() === '+' || peek() === '-') {
const operator = peek();
consume(operator);
const right = parseTerm();
if (operator === '+') {
left += right;
} else {
left -= right;
}
}
return left;
}
try {
const result = parseExpression();
if (index !== expression.length) { // Check for unconsumed characters
throw new Error("Invalid expression: trailing characters");
}
return result;
} catch (error) {
return "Invalid expression: " + error.message;
}
}
// Robust examples
console.log(evaluateExpressionRobust("10 + 5 * 2 - 3 / 3")); // Output: 19
console.log(evaluateExpressionRobust("2 * (5 + 3)")); // Output: 16
console.log(evaluateExpressionRobust("10 / 0")); // Output: Invalid expression: Division by zero (Note improved error message)
console.log(evaluateExpressionRobust("1 + a")); // Output: Invalid expression: Unexpected character: a
console.log(evaluateExpressionRobust("1 + 2)")); // Output: Invalid expression: Unexpected character: )
Explanation and Improvements:
-
eval()
- Simple but Risky: The firstevaluateExpression
function useseval()
. This is concise, but presents security risks if the expression comes from user input (as malicious code could be injected). Avoideval()
in production if possible. -
Robust Parser: The
evaluateExpressionRobust
function demonstrates a basic recursive descent parser. This is a much safer and more controlled way to evaluate expressions. It handles operator precedence (multiplication/division before addition/subtraction) and parentheses correctly. It also provides more informative error messages. -
Error Handling: Both functions include error handling to catch invalid input (like division by zero or incorrect syntax). The robust version provides more specific error messages.
-
Recursive Descent Parsing: The robust parser uses a common technique for parsing expressions. It breaks the problem down into smaller parts (factors, terms, expressions) and recursively calls itself to handle nested expressions and operator precedence