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