基于Node.js和JavaScript实现带乘除优先级的表达式计算
实现带运算符优先级的Node.js控制台计算器
需求概述
开发基于Node.js和readline-sync的控制台应用:
- 接收用户输入的空格分隔数学表达式(如
2 + 3 * 4 / 2 - 1) - 将表达式转为数组,先处理乘除(*、/),再处理加减(+、-),逐步替换计算结果(示例流程:
[2, '+', 12, '/', 2, '-', 1]→[2, '+', 6, '-', 1]→[8, '-', 1]→[7])
当前问题
- 未实现运算符优先级,所有运算按输入顺序执行
- 无法处理包含3个以上运算的表达式
原代码
const readline = require("readline-sync"); const operators = ["+", "-", "*", "/"]; const openParenthesis = ['(', '[', '{']; const closeParenthesis = [')', ']', '}']; var numericOperator = 0; var operatorsList = [] var operatorArray = []; var NumberA = 0; var NumberB = 0; var Total = 0; var soloOperator = ""; var removeValFromIndex = []; var indexOperator = []; var opFound = ""; function askOperator() { operator = readline.question(`make an operation: `) operatorArray = operator.split(' '); console.log(operatorArray, operatorArray.length) } askOperator(); splitArray(operatorArray); function splitArray(sentenceArray) { for (let i = 0; i < sentenceArray.length; i++) { opFound = operators.find(el => el == sentenceArray[i]); if(opFound == "*") { const findMultiplyer = (element) => element == opFound; indexOperator = sentenceArray.findIndex(findMultiplyer); soloOperator = sentenceArray[indexOperator]; NumberA = sentenceArray[indexOperator - 1]; NumberB = sentenceArray[indexOperator + 1]; removeValFromIndex.push((indexOperator - 1), indexOperator, (indexOperator + 1)); for (var j = removeValFromIndex.length -1; j >= 0; j--){ sentenceArray.splice(removeValFromIndex[j],1); } } else if (opFound == "/") { const findDivider = (element) => element == opFound; indexOperator = sentenceArray.findIndex(findDivider); soloOperator = sentenceArray[indexOperator]; NumberA = sentenceArray[indexOperator - 1]; NumberB = sentenceArray[indexOperator + 1]; removeValFromIndex.push((indexOperator - 1), indexOperator, (indexOperator + 1)); for (var j = removeValFromIndex.length -1; j >= 0; j--){ sentenceArray.splice(removeValFromIndex[j],1); } } else if (opFound == "+") { const findAdd = (element) => element == opFound; indexOperator = sentenceArray.findIndex(findAdd); soloOperator = sentenceArray[indexOperator]; NumberA = sentenceArray[indexOperator - 1]; NumberB = sentenceArray[indexOperator + 1]; removeValFromIndex.push((indexOperator - 1), indexOperator, (indexOperator + 1)); for (var j = removeValFromIndex.length -1; j >= 0; j--){ sentenceArray.splice(removeValFromIndex[j],1); } } else if (opFound == "-") { const findMinus = (element) => element == opFound; indexOperator = sentenceArray.findIndex(findMinus); soloOperator = sentenceArray[indexOperator]; NumberA = sentenceArray[indexOperator - 1]; NumberB = sentenceArray[indexOperator + 1]; removeValFromIndex.push((indexOperator - 1), indexOperator, (indexOperator + 1)); for (var j = removeValFromIndex.length -1; j >= 0; j--){ sentenceArray.splice(removeValFromIndex[j],1); } } console.log("loop", opFound, "la", removeValFromIndex ,sentenceArray) } console.log("test", indexOperator, "other", soloOperator, NumberA, NumberB); doMath(NumberA, NumberB) } function doMath(numA, numB) { console.log("index in math", indexOperator) switch (soloOperator) { case '+' : Total = (parseInt(numA) + parseInt(numB)); if (indexOperator > 1) { operatorArray.splice((indexOperator), 0, Total.toString()) } else { operatorArray.splice((indexOperator -1), 0, Total.toString()) } if (operatorArray.length >= 3) { return splitArray(operatorArray) } console.log("addition", Total, "new array", operatorArray ); break; case '-' : Total = numA - numB; if (indexOperator > 1) { operatorArray.splice((indexOperator), 0, Total.toString()) } else { operatorArray.splice((indexOperator -1), 0, Total.toString()) } if (operatorArray.length >= 3) { return splitArray(operatorArray) } console.log("substract", Total, "new array", operatorArray); break; case '*' : Total = numA * numB; if (indexOperator > 1) { operatorArray.splice((indexOperator), 0, Total.toString()) } else { operatorArray.splice((indexOperator -1), 0, Total.toString()) } if (operatorArray.length >= 3) { return splitArray(operatorArray) } console.log(indexOperator,"multiply", Total, "new array", operatorArray); break; case '/' : Total = numA / numB; if (indexOperator > 1) { operatorArray.splice((indexOperator), 0, Total.toString()) } else { operatorArray.splice((indexOperator -1), 0, Total.toString()) } if (operatorArray.length >= 3) { return splitArray(operatorArray) } operatorArray.splice((indexOperator), 0, Total.toString()) console.log("divide", Total, "new array", operatorArray); break; default: console.log("An error occured") break; } }
问题分析
- 优先级未区分:原代码按数组顺序遍历所有运算符,遇到加减或乘除直接处理,没有先处理乘除的逻辑
- 全局变量冲突:
indexOperator、soloOperator等全局变量在递归时会被覆盖,导致多运算处理时状态混乱 - 数组修改逻辑错误:多次
splice删除元素后,索引计算混乱,递归传递的数组状态不一致 - 单次处理不彻底:每次只处理第一个找到的运算符,没有循环处理完同优先级的所有运算
解决方案及优化代码
const readline = require("readline-sync"); // 定义运算符优先级,数字越大优先级越高 const operatorPriority = { '+': 1, '-': 1, '*': 2, '/': 2 }; function askExpression() { const input = readline.question("请输入数学表达式(元素用空格分隔,如 2 + 3 * 4 / 2 - 1):"); return input.split(' '); } // 执行单个运算 function calculate(numA, operator, numB) { const a = parseFloat(numA); const b = parseFloat(numB); switch (operator) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': if (b === 0) throw new Error("除数不能为0"); return a / b; default: throw new Error(`未知运算符:${operator}`); } } // 处理表达式:先处理高优先级,再处理低优先级 function processExpression(exprArray) { let currentArray = [...exprArray]; // 第一步:处理所有乘除(优先级2) let i = 0; while (i < currentArray.length) { const element = currentArray[i]; if (operatorPriority[element] === 2) { const result = calculate(currentArray[i-1], element, currentArray[i+1]); // 替换运算的三个元素为结果 currentArray.splice(i-1, 3, result.toString()); // 替换后回到前一位,重新检查(避免连续乘除漏处理) i = Math.max(i - 1, 0); } else { i++; } } // 第二步:处理所有加减(优先级1) i = 0; while (i < currentArray.length) { const element = currentArray[i]; if (operatorPriority[element] === 1) { const result = calculate(currentArray[i-1], element, currentArray[i+1]); currentArray.splice(i-1, 3, result.toString()); i = Math.max(i - 1, 0); } else { i++; } } // 最终结果应该只剩一个元素 if (currentArray.length !== 1) { throw new Error("表达式格式错误"); } return parseFloat(currentArray[0]); } // 主流程 function main() { try { const exprArray = askExpression(); const result = processExpression(exprArray); console.log(`计算结果:${result}`); } catch (error) { console.error(`错误:${error.message}`); } } main();
优化说明
- 优先级区分:通过
operatorPriority定义优先级,先遍历处理所有乘除,再处理加减 - 局部变量替代全局变量:所有状态变量都是函数内局部变量,避免递归/循环时的状态冲突
- 数组修改逻辑优化:每次处理运算后,用
splice直接替换三个元素为结果,并回退索引,确保连续同优先级运算被处理 - 鲁棒性提升:加入除数为0、表达式格式错误的异常处理
- 支持任意数量运算:循环处理直到数组只剩一个结果元素,兼容多运算表达式
内容的提问来源于stack exchange,提问作者JimmyB
相关产品推荐
相关产品推荐

