您的位置:首页 > 其它

一种字符串表达式求值的简单方法

2007-11-10 00:15 375 查看
在程序设计过程中,可能碰到需要对字符串型数学表达式进行求值,通用且完美的方法是将字符串表达解析,生成表达树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等。
我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式。除此之外,还有前序表达式,后序表达式。如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了。
既然使用生成表达式树的方法直接执行通常的中序表达式有点困难,那就考虑一下其它的两个表达式吧。这里介绍如何用后序表达式来求值,这种方法早在以前就有人介绍了,因为其简单,易实现,故偶在这里重新阐述一下。
后缀表达式——将运算符放在两操作数的后面。后缀表达式也称逆波兰表达式 因其使表达式求值变得轻松,所以被普遍使用。
前缀和后缀表示法有三项公共特征:
1.操作数的顺序与等价的中缀表达式中操作数的顺序一致
2.不需要括号
3.操作符的优先级不相关
当然我们不可能自己特意去写一个后序表达式,这样很难受,因为我们早就习惯了中序表达式这种形式,因此我们需要将中序表达首先转化为后序表达式,去掉括号。中缀转后缀是栈应用的一个典型例子。其转换方法采用运算符优先法。转换过程需借助一个运算符栈和一个存放逆波兰表达式的数组。
转换方法如下:
1.将表达式开始符“#”压入运算符栈,作为栈底元素。
2.读入操作数,直接存入数组。
3.读入运算符,压入运算符栈。
若后进运算符优先级别高于当前栈顶元素时,则继续进栈;
若后进运算符优先级别低于或等于当前栈顶元素时,则将当前栈顶元素出栈,存入数组后进运算符入栈。
4.括号处理
遇到开括号"(",将括号进运算符栈;遇到闭括号")",则把最靠近的开括号,以及该开括号其遇到闭括号,后进栈的运算符依次出栈,存入数组(括号脱去)
5.遇到表达式结束符则把运算符栈内的所有运算符依次弹出,并存入数组。
后缀表达式的执行:
1.先读入两个操作数,遇到操作符,则将这两个操作数进行该操作符对应的计算。
2.保存计算结果,并将其作为下一个操作的第一个操作数。
3.读入下一个操作数,如果已到表达式结尾(即读到空),则算法结束,否则进行第4步
4.读入下一个操作符,进行对应的计算。转第2步。
上面的方法可以使用任意程序设计语言来实现。这里提供一个C#实现的类,该类利用了C#语言特有的一些性质,可以对任意的表达式求值,并且能够解析字符串形式的代码。类代码如下 :


using System;


using System.CodeDom;


using System.CodeDom.Compiler;


using Microsoft.CSharp;


using System.Text;


using System.Reflection;




namespace ADOGuy




...{




/**//// <summary>


/// 此类用于C#计算字符串表达式语句,能计算的语句包括所有的数学表达式:


/// 简单加减乘除表达式:如1+2+2,1*5+1等,


/// 有数学函数的复杂表达:如1+Math.Cos(1),Math.Sqrt(20)等


/// 注意,方法的调用应与表达式的返回结果相对应,否则出错


/// </summary>


public class Evaluator




...{






Construction#region Construction


public Evaluator(EvaluatorItem[] items)




...{


ConstructEvaluator(items);


}


public Evaluator(Type returnType, string expression, string name)




...{




EvaluatorItem[] items = ...{ new EvaluatorItem(returnType, expression, name) };


ConstructEvaluator(items);


}




public Evaluator(string varDefineCode, Type returnType, string expression, string name)




...{




EvaluatorItem[] items = ...{ new EvaluatorItem(varDefineCode, returnType, expression, name) };


ConstructEvaluator(items);


}




public Evaluator(EvaluatorVarDefineItem subItem, Type returnType, string expression, string name)




...{




EvaluatorItem[] items = ...{ new EvaluatorItem(subItem, returnType, expression, name) };


ConstructEvaluator(items);


}




public Evaluator(EvaluatorItem item)




...{




EvaluatorItem[] items = ...{ item };


ConstructEvaluator(items);


}




private void ConstructEvaluator(EvaluatorItem[] items)




...{


ICodeCompiler comp = (new CSharpCodeProvider().CreateCompiler());//有警告,可以试试下一句


//CodeDomProvider comp = new CSharpCodeProvider();




CompilerParameters cp = new CompilerParameters();


cp.ReferencedAssemblies.Add("system.dll");


cp.ReferencedAssemblies.Add("system.data.dll");


cp.ReferencedAssemblies.Add("system.xml.dll");


cp.GenerateExecutable = false;


cp.GenerateInMemory = true;




StringBuilder code = new StringBuilder();//将要编译的代码串写入code


code.Append("using System; ");


code.Append("namespace ADOGuy { ");


code.Append(" public class _Evaluator { ");


foreach (EvaluatorItem item in items)




...{


code.AppendFormat(" public {0} {1}() ",


item.ReturnType.Name,


item.Name);


code.Append("{ ");


code.Append(item.VarDefineCode + " ");


code.AppendFormat(" return ({0}); ", item.Expression);


code.Append("} ");


}


code.Append("} }");




Console.WriteLine(code);




CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString());//从code串构建程序


if (cr.Errors.HasErrors)




...{


StringBuilder error = new StringBuilder();


error.Append("Error Compiling Expression: ");


foreach (CompilerError err in cr.Errors)




...{


error.AppendFormat("{0} ", err.ErrorText);


}


throw new Exception("Error Compiling Expression: " + error.ToString());


}


Assembly a = cr.CompiledAssembly;


_Compiled = a.CreateInstance("ADOGuy._Evaluator");//创建程序实例


}


#endregion






Public Members#region Public Members


public int EvaluateInt(string name)




...{


return Convert.ToInt32(Evaluate(name));


}




public string EvaluateString(string name)




...{


return Convert.ToString(Evaluate(name));


}




public bool EvaluateBool(string name)




...{


return Convert.ToBoolean(Evaluate(name));


}




public float EvaluateFloat(string name)




...{


return Convert.ToSingle(Evaluate(name));


}




public double EvaluateDouble(string name)




...{


return Convert.ToDouble(Evaluate(name));


}




public object EvaluateObject(string name)




...{


return Evaluate(name);


}




public object Evaluate(string name)




...{


MethodInfo mi = _Compiled.GetType().GetMethod(name);//利用实例调用由name指定的方法进行计算


return mi.Invoke(_Compiled, null);


}


#endregion






Static Members#region Static Members


static public int EvaluateToInteger(string code)




...{


Evaluator eval = new Evaluator(typeof(int), code, staticMethodName);


return Convert.ToInt32(eval.Evaluate(staticMethodName));


}




static public string EvaluateToString(string code)




...{


Evaluator eval = new Evaluator(typeof(string), code, staticMethodName);


return Convert.ToString(eval.Evaluate(staticMethodName));


}






static public bool EvaluateToBool(string code)




...{


Evaluator eval = new Evaluator(typeof(bool), code, staticMethodName);


return Convert.ToBoolean(eval.Evaluate(staticMethodName));


}




static public double EvaluateToDouble(string code)




...{


Evaluator eval = new Evaluator(typeof(double), code, staticMethodName);


return Convert.ToDouble(eval.Evaluate(staticMethodName));


}




static public object EvaluateToObject(string code)




...{


Evaluator eval = new Evaluator(typeof(object), code, staticMethodName);


return eval.Evaluate(staticMethodName);


}


static public int EvaluateToInteger(string varDefineCode, string code)




...{




Evaluator eval = new Evaluator(varDefineCode, typeof(int), code, staticMethodName);


return Convert.ToInt32(eval.Evaluate(staticMethodName));


}




static public string EvaluateToString(string varDefineCode, string code)




...{


Evaluator eval = new Evaluator(varDefineCode, typeof(string), code, staticMethodName);


return Convert.ToString(eval.Evaluate(staticMethodName));


}






static public bool EvaluateToBool(string varDefineCode, string code)




...{


Evaluator eval = new Evaluator(varDefineCode, typeof(bool), code, staticMethodName);


return Convert.ToBoolean(eval.Evaluate(staticMethodName));


}




static public double EvaluateToDouble(string varDefineCode, string code)




...{


Evaluator eval = new Evaluator(varDefineCode, typeof(double), code, staticMethodName);


return Convert.ToDouble(eval.Evaluate(staticMethodName));


}




static public object EvaluateToObject(string varDefineCode, string code)




...{


Evaluator eval = new Evaluator(varDefineCode, typeof(object), code, staticMethodName);


return eval.Evaluate(staticMethodName);


}




#endregion






Private#region Private


const string staticMethodName = "__foo";


Type _CompiledType = null;


object _Compiled = null;


#endregion


}






...#region


public class EvaluatorItem




...{


public EvaluatorItem(Type returnType, string expression, string name)




...{


ReturnType = returnType;


Expression = expression;


Name = name;


}




public EvaluatorItem(string varDefineCode, Type returnType, string expression, string name)




...{


VarDefineCode = varDefineCode;


ReturnType = returnType;


Expression = expression;


Name = name;


}




public EvaluatorItem(EvaluatorVarDefineItem subItem, Type returnType, string expression, string name)




...{


VarDefineCode = subItem.getVarDefineCode();


ReturnType = returnType;


Expression = expression;


Name = name;


}




public string VarDefineCode = "";


public Type ReturnType;


public string Name;


public string Expression;


}


#endregion






...#region


public class EvaluatorVarDefineItem




...{


private string VarDefineCode = "";






public EvaluatorVarDefineItem()...{}




public EvaluatorVarDefineItem(Type varType, string varName, string varValue)




...{


this.VarDefineCode = varType.Name + " " + varName.Trim() + " = " + varValue.Trim() + ";";


}




public EvaluatorVarDefineItem(Type varType, string varExpression)




...{


this.VarDefineCode = varType.Name + " " + varExpression + ";";


}




public string getVarDefineCode()




...{


return this.VarDefineCode;


}




public void addVarExpression(Type varType, string varName, string varValue)




...{


this.VarDefineCode += " "+varType.Name + " " + varName.Trim() + " = " + varValue.Trim() + ";";


}




public void addVarExpression(Type varType, string varExpression)




...{


this.VarDefineCode += " " + varType.Name + " " + varExpression + ";";


}


};


#endregion


}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐