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

如何不依赖外部crate实现字符串算术表达式顺序计算(无优先级)

左到右无优先级算术表达式计算(Rust实现问题)

需求

不依赖外部crate,将字符串形式的算术表达式按左到右顺序直接计算(不遵循常规运算符优先级)。例如输入 "500+10-66*32",预期计算过程为:
((500+10)-66)*32 = 444*32 = 14208

当前问题

已成功实现加减运算,但乘除的左到右顺序处理逻辑存在错误,无法得到正确结果。

现有代码

//a = ‘+’, b = ‘-’, c = ‘*’, d = ‘/’, e = ‘(’, f = ‘)’
use std::collections::VecDeque;
fn calculate(s: String) -> i32 {
    let mut multi_active = false;
    const SPACE: char = ' ';
    const SIGN_PLUS: char = '+';
    const SIGN_MINUS: char = '-';
    const SIGN_MULTIPLY: char = '*';
    const SIGN_DIVIDE: char = '/';
    const PAREN_OPEN: char = '(';
    const PAREN_CLOSED: char = ')';
    let len_s: usize = s.len();
    let mut num: i32 = 0;
    let mut ans: i32 = 0;
    let mut sign: i32 = 1;
    let mut stk: VecDeque<i32> = VecDeque::with_capacity(len_s);
    stk.push_back(sign);
    for ch in s.chars() {
      println!("chars:{}",ch);
        match ch {
            '0'..='9' => {
                num = num * 10 + (ch as i32 - '0' as i32);
                println!("given numbers:{num}");
            }
            SIGN_PLUS | SIGN_MINUS => {
                ans += sign * num;
                sign = stk.back().unwrap() * if ch == SIGN_PLUS { 1 } else { -1 };
                num = 0;
                multi_active = false;

            }
            PAREN_OPEN => {
                stk.push_back(sign);
            }
            PAREN_CLOSED => {
                stk.pop_back();
            }
            SIGN_MULTIPLY => {
                 println!("b4 ans = {ans}");
                 println!("b4 sig = {sign}");
                 println!("b4 num = {num}");
                  ans = ans + sign * num;
                println!("simple multi- {}", ans);
                sign = stk.back().unwrap() * if ch == SIGN_MULTIPLY { 1 } else { -1 };
                num = 0;
              multi_active = true;
            }
            _ => {}
        }
    }
    println!("final:{ans}@@@@{sign}@@@@{num}===={:?}",multi_active);
    ans = ans + sign * num;
    ans
}

fn main() {
    let inputs = "2+44+6+1".to_owned();
    let outs = calculate(inputs);
    println!("{outs}");
}

问题分析

现有代码的核心错误在于:处理乘除时,错误地将当前数值通过sign累加到ans中,而没有直接对ans(当前计算结果)和num执行乘除运算。左到右计算要求每遇到一个运算符,就立即用前一步的结果和当前数值完成运算,而非延迟到最后累加。

修复后的代码

use std::collections::VecDeque;

fn calculate(s: String) -> i32 {
    const SIGN_PLUS: char = '+';
    const SIGN_MINUS: char = '-';
    const SIGN_MULTIPLY: char = '*';
    const SIGN_DIVIDE: char = '/';
    const PAREN_OPEN: char = '(';
    const PAREN_CLOSED: char = ')';

    let mut num = 0;
    // 栈用于保存括号前的计算结果和运算符
    let mut stack: VecDeque<(i32, char)> = VecDeque::new();
    // 当前的计算结果和当前等待的运算符
    let mut current_result = 0;
    let mut current_op = SIGN_PLUS;

    for ch in s.chars() {
        match ch {
            '0'..='9' => {
                num = num * 10 + (ch as i32 - '0' as i32);
            }
            SIGN_PLUS | SIGN_MINUS | SIGN_MULTIPLY | SIGN_DIVIDE => {
                // 先执行上一个运算符的计算
                current_result = match current_op {
                    SIGN_PLUS => current_result + num,
                    SIGN_MINUS => current_result - num,
                    SIGN_MULTIPLY => current_result * num,
                    SIGN_DIVIDE => current_result / num, // 整数除法按Rust默认向零取整
                    _ => current_result,
                };
                current_op = ch;
                num = 0;
            }
            PAREN_OPEN => {
                // 保存当前状态到栈中
                stack.push_back((current_result, current_op));
                // 重置当前状态,处理括号内的表达式
                current_result = 0;
                current_op = SIGN_PLUS;
            }
            PAREN_CLOSED => {
                // 先完成括号内最后一步计算
                current_result = match current_op {
                    SIGN_PLUS => current_result + num,
                    SIGN_MINUS => current_result - num,
                    SIGN_MULTIPLY => current_result * num,
                    SIGN_DIVIDE => current_result / num,
                    _ => current_result,
                };
                num = 0;
                // 弹出栈中保存的状态,合并结果
                let (prev_result, prev_op) = stack.pop_back().unwrap();
                current_result = match prev_op {
                    SIGN_PLUS => prev_result + current_result,
                    SIGN_MINUS => prev_result - current_result,
                    SIGN_MULTIPLY => prev_result * current_result,
                    SIGN_DIVIDE => prev_result / current_result,
                    _ => current_result,
                };
            }
            _ => {} // 忽略空格
        }
    }

    // 处理最后一个数字
    current_result = match current_op {
        SIGN_PLUS => current_result + num,
        SIGN_MINUS => current_result - num,
        SIGN_MULTIPLY => current_result * num,
        SIGN_DIVIDE => current_result / num,
        _ => current_result,
    };

    current_result
}

fn main() {
    let input1 = "500+10-66*32".to_owned();
    println!("{}", calculate(input1)); // 输出14208

    let input2 = "2+44+6+1".to_owned();
    println!("{}", calculate(input2)); // 输出53

    let input3 = "(10+5)*3".to_owned();
    println!("{}", calculate(input3)); // 输出45(左到右计算:(15)*3=45)
}

修复说明

  1. 用current_result维护当前的计算结果,遇到运算符时立即执行上一步运算,确保左到右的顺序;
  2. 用栈处理括号:遇到左括号时保存当前计算状态,处理完括号内表达式后,将结果与括号前的状态合并;
  3. 统一处理加减乘除的运算逻辑,确保每一步都直接计算,无优先级区分;
  4. 最后处理表达式末尾的数字,完成最终计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:24:37