有时候需要表达式运算,如 String strExpression="-12 * ( - 2.2 + 7.7 ) - 44 * 2";
网上找的,一般是利用CodeDom,见 http://www.codeproject.com/csharp/runtime_eval.asp
简化为: System.CodeDom.Compiler.ICodeCompiler comp = (new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler()); System.CodeDom.Compiler.CompilerParameters cp = new System.CodeDom.Compiler.CompilerParameters();
object qswhEval2(string Expression){ StringBuilder code = new StringBuilder(); code.Append("using System; \n"); code.Append("namespace ADOGuy { \n"); code.Append(" public class _Evaluator { \n"); code.Append(" public object __foo() "); code.Append("{ "); code.AppendFormat(" return ({0}); ", Expression); code.Append("}\n"); code.Append("} }"); System.CodeDom.Compiler.CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString()); System.Reflection.Assembly a = cr.CompiledAssembly; object _Compiled = a.CreateInstance("ADOGuy._Evaluator"); System.Reflection.MethodInfo mi = _Compiled.GetType().GetMethod("__foo"); return mi.Invoke(_Compiled, null); }
但用起来感觉很慢,毕竟需要实时编译。
于是,就自己照数据结构书上写了一种算法: string Precede(string p, string q){ switch(p){ case "+": case "-":return ("*/(".IndexOf(q)!=-1)?"<":">"; case "*": case "/":return (q=="(")?"<":">"; case "(":return (q==")")?"=":"<"; case ")":return (q=="(")?"?":">"; case "#":return (q=="#")?"=":"<"; } return "?"; } Double Operate(Double a,char o,Double b) { switch(o) { case '+':return a+b; case '-':return a-b; case '*':return a*b; case '/':return a/b; } return 0; }
Object qswhEval1(string Expression){ /*************(qiushuiwuhen 2002-12-14)****************/ Stack nArr=new Stack(),oArr=new Stack(); int j=0; Double a=0,b=0; string w=""; char o; MatchCollection arr=Regex.Matches(Expression.Replace(" ","")+"#",@"(((?<=(^|\())-)?\d+(\.\d+)?|\D)"); oArr.Push('#'); w=Convert.ToString(arr[j++]); while(!(w=="#"&&Convert.ToString(oArr.Peek())=="#")){ if("+-*/()#".IndexOf(w)!=-1){ switch(Precede(oArr.Peek().ToString(),w)){ case "<": oArr.Push(w); w=Convert.ToString(arr[j++]); break; case "=": oArr.Pop(); w=Convert.ToString(arr[j++]); break; case ">": o=Convert.ToChar(oArr.Pop()); b=Convert.ToDouble(nArr.Pop()); a=Convert.ToDouble(nArr.Pop()); nArr.Push(Operate(a,o,b)); break; default: return "Error"; break; } }else{ nArr.Push(w); w=Convert.ToString(arr[j++]); } } return nArr.Pop(); }
还有利用JScript的Eval的两种算法 Microsoft.JScript.Vsa.VsaEngine ve=Microsoft.JScript.Vsa.VsaEngine.CreateEngine(); object qswhEval3(string Expression){ return Microsoft.JScript.Eval.JScriptEvaluate(Expression,ve); }
object qswhEval4(string Expression){ return qswhJs.qswhEval.Eval(Expression); }
第四种需先建立一js编译为dll,如下代码 import System;
package qswhJs { class qswhEval { static function Eval(Expression):Object { return eval(Expression); } } }
测试代码如下: void Page_Load(Object o,EventArgs ea){ String strExpression="-12 * ( - 2.2 + 7.7 ) - 44 * 2"; int i=0,c=100; DateTime d1,d2; cp.GenerateExecutable = false; cp.GenerateInMemory = true; d1=DateTime.Now; for(i=0;i<c;i++)qswhEval1(strExpression); d2=DateTime.Now; Response.Write("方法一:对表达式分析 "+d2.Subtract(d1)+"<br>"); d1=DateTime.Now; for(i=0;i<c;i++)qswhEval2(strExpression); d2=DateTime.Now; Response.Write("方法二:利用CodeCom "+d2.Subtract(d1)+"<br>"); d1=DateTime.Now; for(i=0;i<c;i++)qswhEval3(strExpression); d2=DateTime.Now; Response.Write("方法三:利用Jscript+Vsa "+d2.Subtract(d1)+"<br>"); d1=DateTime.Now; for(i=0;i<c;i++)qswhEval4(strExpression); d2=DateTime.Now; Response.Write("方法四:利用Jsc+Dll "+d2.Subtract(d1)+"<br>"); }
测试结果:
方法一:对表达式分析 00:00:00.1702448 方法二:利用CodeCom 00:00:23.7942144 方法三:利用Jscript+Vsa 00:00:00.1902736 方法四:利用Jsc+Dll 00:00:00.2403456
在此推荐第一种(如果要纯CSharp的话) 和第三种(代码简单,功能更多) 
|