You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Node.js和JavaScript实现带乘除优先级的表达式计算

实现带运算符优先级的Node.js控制台计算器

需求概述

开发基于Node.js和readline-sync的控制台应用:

  • 接收用户输入的空格分隔数学表达式(如2 + 3 * 4 / 2 - 1)
  • 将表达式转为数组,先处理乘除(*、/),再处理加减(+、-),逐步替换计算结果(示例流程:[2, '+', 12, '/', 2, '-', 1] → [2, '+', 6, '-', 1] → [8, '-', 1] → [7])

当前问题

  1. 未实现运算符优先级,所有运算按输入顺序执行
  2. 无法处理包含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;
        }

}

问题分析

  1. 优先级未区分:原代码按数组顺序遍历所有运算符,遇到加减或乘除直接处理,没有先处理乘除的逻辑
  2. 全局变量冲突:indexOperator、soloOperator等全局变量在递归时会被覆盖,导致多运算处理时状态混乱
  3. 数组修改逻辑错误:多次splice删除元素后,索引计算混乱,递归传递的数组状态不一致
  4. 单次处理不彻底:每次只处理第一个找到的运算符,没有循环处理完同优先级的所有运算

解决方案及优化代码

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();

优化说明

  1. 优先级区分:通过operatorPriority定义优先级,先遍历处理所有乘除,再处理加减
  2. 局部变量替代全局变量:所有状态变量都是函数内局部变量,避免递归/循环时的状态冲突
  3. 数组修改逻辑优化:每次处理运算后,用splice直接替换三个元素为结果,并回退索引,确保连续同优先级运算被处理
  4. 鲁棒性提升:加入除数为0、表达式格式错误的异常处理
  5. 支持任意数量运算:循环处理直到数组只剩一个结果元素,兼容多运算表达式

内容的提问来源于stack exchange,提问作者JimmyB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:10:30