如何不依赖外部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) }
修复说明
- 用
current_result维护当前的计算结果,遇到运算符时立即执行上一步运算,确保左到右的顺序; - 用栈处理括号:遇到左括号时保存当前计算状态,处理完括号内表达式后,将结果与括号前的状态合并;
- 统一处理加减乘除的运算逻辑,确保每一步都直接计算,无优先级区分;
- 最后处理表达式末尾的数字,完成最终计算。
内容的提问来源于stack exchange,提问作者sachin murali
相关产品推荐
相关产品推荐

