表达式的计算主要有两种方法:
1.动态编译
2.语法分析
下面具体说说每种方法
1.动态编译
动创建一个类和一个方法,这个方法的很简单就是你的表达式。代码如下,这是性能最差的方法
public static object Calculate(string expression)
{
string className = "Calc";
string methodName = "Run";
// 创建编译器实例。
//ICodeCompiler complier = (new CSharpCodeProvider().CreateCompiler()); //旧版实现方式
CodeDomProvider complier = new CSharpCodeProvider();
// 设置编译参数。
CompilerParameters paras = new CompilerParameters();
paras.GenerateExecutable = false;
paras.GenerateInMemory = true;
// 创建动态代码。
StringBuilder classSource = new StringBuilder();
classSource.Append("public class " + className + "\n");
classSource.Append("{\n");
classSource.Append(" public object " + methodName + "()\n");
classSource.Append(" {\n");
classSource.Append(" return " + expression + ";\n");
classSource.Append(" }\n");
classSource.Append("}");
// 编译代码。
CompilerResults result = complier.CompileAssemblyFromSource(paras, classSource.ToString());
// 获取编译后的程序集。
Assembly assembly = result.CompiledAssembly;
// 动态调用方法。
object eval = assembly.CreateInstance(className);
MethodInfo method = eval.GetType().GetMethod(methodName);
object reobj = method.Invoke(eval, null);
GC.Collect();
return reobj;
}
}
2.语法分析
有很多方法,推荐逆波兰栈的方式实现。这个比较简单性能很好。
在网上找了很久,找到帮助最大的资料如下:
http://www.cnblogs.com/michaelhuwei/archive/2008/03/26/1123401.html
这个代码发现了一个Bug.
ROUND((14.5 - 14.0) / 0.5,1) * 0.75
计算结果:0.00 而正确的结果是:0.75
调试发现处理逗号的时候出现问题造成rpn表达式错误
//下面是您的代码
if (!valid)
throw new ExpressionException("逗号不允许出现在函数体外.", 2001);
else
{
//此处有问题,假如栈顶是+ - * /必须添加上如下代码
opBk = _stackOp.Peek();
if (opBk < OperatorType.L_Parentheses)
{
_rePoland.Add(new ExpressionToken(TokenType.Operator, opBk));
_stackOp.Pop();
}
//这样逆波兰表达式由错误的:14.5 14 - 0.5 1 / ROUND 0.75 *
-> 14.5 14 - 0.5 / 1 ROUND 0.75 *
needOp = false;
stackOp.Push(OperatorType.Comma);
}
网上还有一位写的代码也能执行成功,但是性能较差,当然与上面的相比。
我粗略的看了一下发现他首先判断输入的表达式是否合法。推荐上面的方法。不必要在你
解析的时候判断即可。性能差很多
http://www.cnblogs.com/lxfqlcz/archive/2011/08/02/2124854.html
www.codeproject.com上也有这方面的资料,但是都不尽如人意。
要想详细看具体实现请到他们各自的博客上看。
希望原作者见谅!
另外在www.codeplex.com有个轻量级的 Flee也很好用。他也是语法分析。原先在pc上就用的这个。
但是后来用到windows ce. net上了。这个不行了。才有此想法查找资料。
计算逆波兰表达式使用Queue(队列)在此文章的基础上可以优化,待续...
搜索关键词: Math Parser 表达式计算 逆波兰