ERP系统业务繁杂,为应对变化,通常会用到公式编辑器。联想到大学学过的汇编原理,国庆期间一个人没事干,就略微温习了下,花了几个小时写了个公式编辑器。面向对象搞多了,算法能力和记忆力都慢慢弱化了,呜呼哀哉!
本公式编辑器实现的功能很简单,就是计算加减乘除。未进行公式的校验,也未涉及逻辑运算,目的只是单纯地温习下大学的理论基础,同时希望能给其他人一些启发。采用逆波兰式算法,运行结果如下所示。下载源代码
实现代码如下:
public class CalculateHelper { //定义算术运算符的优先级 private int GetOperatorPriorityLevel(char oper) { switch (oper) { case '#': return 0; case '+': return 1; case '-': return 1; case '*': return 2; case '/': return 2; default: return -1; } } //oper1优先级高于oper2,返回正数,反之返回负数,相等则返回0 private int ComparePriority(char oper1, char oper2) { return GetOperatorPriorityLevel(oper1) - GetOperatorPriorityLevel(oper2); } //中缀表达式转后缀表达式 public Queue<string> MiddleToSuffix(string expression) { Stack<char> temporaryStack = new Stack<char>(); temporaryStack.Push('#'); Queue<string> suffixExpression = new Queue<string>(); string temNum = ""; for (int i = 0; i < expression.Length; i++) { if (expression[i] == ' ')//过滤空格 continue; #region 处理数字 if (char.IsNumber(expression[i]) || expression[i] == '.') { temNum += expression[i]; if ((i == expression.Length - 1))//字符串已经处理结束 suffixExpression.Enqueue(temNum); continue; } else { if (temNum != "") suffixExpression.Enqueue(temNum); temNum = ""; } #endregion #region 处理括号 if (expression[i] == '(') temporaryStack.Push(expression[i]); else if (expression[i] == ')') { while (temporaryStack.Peek() != '#') //退栈并输出,直至遇到 '(' { char top = temporaryStack.Pop(); if (top == '(') break; suffixExpression.Enqueue(top.ToString()); } } #endregion #region 处理运算符 else // 是运算符,比较优先级 { char top = temporaryStack.Peek(); while (ComparePriority(expression[i], top) <= 0)//保证栈顶元素优先级最高 { suffixExpression.Enqueue(top.ToString()); temporaryStack.Pop(); top = temporaryStack.Peek(); } if (expression[i] != ')') //右括号不入栈 temporaryStack.Push(expression[i]); } #endregion } while (temporaryStack.Count > 1) suffixExpression.Enqueue(temporaryStack.Pop().ToString()); return suffixExpression; } private double Calculate(string operand1, string operand2, string oper) { double oper1 = double.Parse(operand1); double oper2 = double.Parse(operand2); switch (oper) { case "+": return oper1 + oper2; case "-": return oper1 - oper2; case "*": return oper1 * oper2; case "/": return oper1 / oper2; default: throw new Exception("操作符有误!"); } } //计算中缀表达式的结果 public double GetResult(string expression) { Queue<string> suffixExpression = MiddleToSuffix(expression); Stack<string> resultStack = new Stack<string>(); while (suffixExpression.Count() > 0) { string oper = suffixExpression.Dequeue(); if (oper == "+" || oper == "-" || oper == "*" || oper == "/")//为操作符,就计算 { string oper2 = resultStack.Pop(); string oper1 = resultStack.Pop(); string temresult = Calculate(oper1, oper2, oper).ToString(); resultStack.Push(temresult); } else resultStack.Push(oper); } string result = resultStack.Pop(); return double.Parse(result); } }