C#四则运算字符串计算函数优化方案咨询
遗漏的边界情况
- 空白字符处理:输入包含空格、制表符等空白字符时,会被识别为数字的一部分,导致
decimal.Parse抛出格式异常 - 非法字符校验:输入混入非数字、非小数点、非指定运算符的字符(比如字母、中文、括号等)时,没有前置校验,直接抛出解析异常
- 异常表达式处理:表达式首尾为运算符、连续出现多个运算符、数字包含多个小数点的场景,会生成空token或无效数字token,直接报错
- 负数场景:以负号开头的表达式(比如
-10+3)、运算符后紧跟负号的表达式(比如5+-2.5)无法正确识别,会生成空数字token - 除零异常:除数为0时直接抛出系统默认异常,没有自定义处理逻辑
可优化点
1. 分词逻辑优化
- 遍历前先移除所有空白字符,避免空格干扰
- 用
StringBuilder代替字符串拼接数字,减少托管内存分配 - 增加负号识别逻辑:当负号出现在表达式首位、或者前面是运算符时,将负号归入当前数字的一部分
- 提前校验数字格式,避免多个小数点的情况
2. 逆波兰转换逻辑优化
- 抽取运算符优先级判断方法,避免重复写判断条件,代码更易维护,示例:
private static int GetOpPriority(string op) => op switch { "×" or "÷" => 2, "+" or "-" => 1, _ => 0 };
- 优先级比较直接对比数值即可,不需要多分支判断,简化逻辑
3. 逆波兰计算逻辑优化
原有实现通过修改逆波兰列表、重置索引的方式计算,时间复杂度为O(n²),性能较差。可以改为标准栈计算逻辑,时间复杂度降为O(n),代码也更简洁:
Stack<decimal> calcStack = new Stack<decimal>(); foreach (var token in splittedPostFixExp) { if (decimal.TryParse(token, out var num)) { calcStack.Push(num); continue; } if (calcStack.Count < 2) throw new InvalidOperationException("表达式格式非法"); var right = calcStack.Pop(); var left = calcStack.Pop(); var result = token switch { "+" => left + right, "-" => left - right, "×" => left * right, "÷" => right == 0 ? throw new DivideByZeroException("除数不能为0") : left / right, _ => throw new NotSupportedException($"不支持的运算符:{token}") }; calcStack.Push(result); } if (calcStack.Count != 1) throw new InvalidOperationException("表达式格式非法"); return calcStack.Pop();
4. 异常处理优化
统一捕获各类异常,抛出带明确提示的自定义异常,方便上层调用方处理,避免直接抛出系统底层异常。
现成实现方案
- 如果你不想自己维护算法逻辑,可以直接用.NET内置的
DataTable.Compute方法,只需提前把×替换为*、÷替换为/即可,示例:
using System.Data; private static decimal CalculateExpression(string input) { var processedExp = input.Replace("×", "*").Replace("÷", "/"); var result = new DataTable().Compute(processedExp, null); return Convert.ToDecimal(result); }
该方法对四则运算的支持完全符合你的需求,不需要额外引入第三方依赖。
- 如果后续需要扩展更复杂的表达式计算能力,可以引入NCalc等第三方表达式解析库,支持自定义函数、参数等能力。
内容的提问来源于stack exchange,提问作者Decker
相关产品推荐
相关产品推荐

