以前在一个项目里面用到东西, 我在GOOGLE里面搜索, 没有找到答案, 却因此认识了www.cnblogs.com, 发现这才是我喜欢的地方. 现在加入了博客园, 把当时写的东西贴出来,看看对遇到同样问题的网友有没有帮助. 也作为我的第一篇BLOG吧! 本人菜鸟一只, 不对的地方还望大家多多指教.
/*
简介: 使用栈结构,没有使用大家常用的前后缀表达式, 因为考虑到要添加自定义函数, 便用前后缀表达式的方法还不会实现, 现在还不支持嵌套, 看下哪位大虾有方法解决.
Evaluator.cs:
*/
using System;
using System.Collections;
namespace F5
{
/// <summary>
/// 表达式计算类
///
/// 描述:
/// 表达式示例: 2+3*EXP(3.3*X, 5)/3-2*(3+2/2*X)/2-3
/// 说明:
/// .为简化算法,表达式中无正、负号,要得到负号的作用请用 (1-2)*? 来表示
/// .表达式中的元素(现区分大小写)有:
/// 数值常数(包括小数点): 如: 3.2 8.3
/// 运算符: 如: + - * /
/// 括号: ( )
/// 变量: 运算时将实际值代入其中,用一单词(字符串,原则上不应包括数字)来表示, 赋值时用类的索引器表示 如: X Y Delta
/// 用户自定义函数: 函数的操作要用括号()括起来,里面的表达式用递归来求 如: EXP(2+3*X, 2), 但是函数里的表达式不能再有函数(即用户自定义函数不允许递归)
/// 分隔符: 空格(不会放入符号栈中) 逗号(用于用户自定义函数中,分隔各参数,要放入栈中), 各运算符默认已是分隔符
/// .算法中要用到的:
/// 单词解析函数: 将表达式中的各元素解析放到一字符串数组中(其中的每一字符串表示一个元素)
/// 单词表(数组): 存放单词解析函数解析的元素
/// 符号栈: 运算时存放符号
/// 数值栈: 运算时存放数值(及中间值)
/// 解析函数: 核心,对表达式作运算并求出最终结果
/// </summary>
public class Evaluator
{
#region 表达式计算必要的前期设计内容
/// <summary>
/// 数值栈
/// </summary>
public class ValStack
{
private Stack stack=new Stack();
/// <summary>
/// 弹出栈顶值
/// </summary>
/// <returns>栈为空则抛异常</returns>
public double Pop()
{
if(stack.Count==0)
return 0;
else
return (double)stack.Pop();
}
/// <summary>
/// 向栈中压入值
/// </summary>
/// <param name="val"></param>
public void Push(double val)
{
stack.Push(val);
}
/// <summary>
/// 取栈顶值,但不弹出
/// </summary>
/// <returns></returns>
public double Peek()
{
if(stack.Count==0)
return 0;
else
return (double)stack.Peek();
}
/// <summary>
/// 栈中数值个数
/// </summary>
public int Count
{
get
{
return stack.Count;
}
}
/// <summary>
/// 清空栈
/// </summary>
public void Clear()
{
stack.Clear();
}
}
/// <summary>
/// 符号栈
/// </summary>
public class SignStack
{
private Stack stack=new Stack();
/// <summary>
/// 弹出栈顶值
/// </summary>
/// <returns>栈为空则抛异常</returns>
public string Pop()
{
if(stack.Count==0)
return "";
else
return (string)stack.Pop();
}
/// <summary>
/// 向栈中压入值
/// </summary>
/// <param name="val"></param>
public void Push(string val)
{
stack.Push(val);
}
/// <summary>
/// 取栈顶值,但不弹出
/// </summary>
/// <returns></returns>
public string Peek()
{
if(stack.Count==0)
return "";
else
return (string)stack.Peek();
}
/// <summary>
/// 栈中字符串个数
/// </summary>
public int Count
{
get
{
return stack.Count;
}
}
/// <summary>
/// 清空栈
/// </summary>
public void Clear()
{
stack.Clear();
}
}
/// <summary>
/// 单词解析
/// </summary>
public class WordAnalysis
{
/// <summary>
/// 默认分隔符(有分隔单词功能的符号,因此包括一些运算符), 用户可以自定义这些分隔符
/// </summary>
public static string[] Seperator=new string[]
{
"+", "-", "*", "/", ",", "(", ")", "ABC"
};
/// <summary>
/// 指定字符是否为分隔符
/// </summary>
/// <param name="s">字符</param>
/// <returns></returns>
public static bool IsSeperator(string s)
{
for(int i=0;i<Seperator.Length;i++)
if(s==Seperator[i])
return true;
return false;
}
#region Analysis_Old
/*
/// <summary>
/// 单词分析,过时. 如果分析的分隔符由2个及以上字符组成会出错.
/// </summary>
/// <param name="str">字符串</param>
/// <returns></returns>
private static string[] Analysis_Old(string str)
{
ArrayList list=new ArrayList();
string cur="";
for(int i=0;i<str.Length;i++) //循环扫描字符串中的每个字符
{
if(IsSeperator(str[i].ToString()))
{
if(cur!="")
list.Add(cur);
cur=
str[i]==' ' ? "" : str[i].ToString(); //为空格则舍去,为其它分隔符(如:+-* /)则保留
}
else
{
if(cur!="" && IsSeperator(cur[0].ToString()))
{
list.Add(cur);
cur="";
}
cur+=str[i].ToString();
}
}
if(cur!="")
list.Add(cur);
string[] ret=new string[list.Count];
for(int i=0; i<list.Count;i++)
ret[i]=(string)list[i];
return ret;
}
*/
#endregion
/// <summary>
/// 单词分析
/// 空格, TAB, 回车 一定是分隔符
/// 如果分隔符由多个字符组成, 则分隔符的第一个字符前要有空格,TAB或回车符
/// </summary>
/// <param name="str">字符串</param>
/// <returns></returns>
public static string[] Analysis(string str)
{
if( str == null || str == "")
{
throw new Exception("表达式不能为NULL 或 空 ");
}
ArrayList list=new ArrayList();
string cur="";
for(int i=0;i<str.Length;i++) //循环扫描字符串中的每个字符
{
string t=str[i].ToString();
if(t==" " || t=="\t" || t=="\n")
{
if(cur!="")
{
list.Add(cur);
cur="";
}
}
else if(IsSeperator(t))
{
if(cur!="")
{
list.Add(cur);
cur="";
}
list.Add(t);
}
else
{
cur+=t;
if(IsSeperator(cur.Trim()))
{
list.Add(cur);
cur="";
}
}
}
if(cur!="")
list.Add(cur);
string[] ret=new string[list.Count];
for(int i=0; i<list.Count;i++)
ret[i]=(string)list[i];
return ret;
}
}
/// <summary>
/// 变量操作结构
/// </summary>
public struct Variable
{
private string[] Key;
private double[] Value;
private int index; //已分配的变量个数
/// <summary>
/// 初始化
/// </summary>
/// <param name="size">允许的最大变量个数变量</param>
public Variable(int size)
{
Key=new string[size];
Value=new double[size];
for(int i=0;i<Key.Length;i++)
{
Key[i]="";
Value[i]=0;
}
index=0;
}
/// <summary>
/// 获取或设置指定变量的值
/// </summary>
public double this[string key]
{
get
{
int idx=IndexOf(key);
if(idx==-1)
{
// throw new Exception("变量"+key+"在数组中不存在");
return 0; //考虑到算法的稳定性, 不抛异常
}
else
{
return Value[idx];
}
}
set
{
int idx=IndexOf(key);
if(idx==-1)
{
if(index<this.Length) //还有容量
{
Key[index]=key;
Value[index]=value;
index++;
}
else throw new Exception("新增变量出错, 变量数组已满"); //现暂不抛异常
}
else
Value[idx]=value;
}
}
/// <summary>
/// 返回变量在数组中的索引(位置)
/// </summary>
/// <param name="key">变量名</param>
/// <returns>不存在返回-1, 否则返回>=0的整数</returns>
public int IndexOf(string key)
{
if(key==null || key=="")
return -1;
else
{
for(int i=0;i<index;i++)
if(Key[i]==key)
return i;
return -1;
}
}
/// <summary>
/// 返回已声明变量个数
/// </summary>
public int Count
{
get
{
return index;
}
}
/// <summary>
/// 变量数组最大容量
/// </summary>
public int Length
{
get
{
return Key.Length;
}
}
}
/// <summary>
/// 用户自定义函数代理
/// </summary>
public delegate double Function(
// string functionName, //自定义函数在表达式中的别名
// Variable var // 参数所在变量结构数组
params double[] param //函数计算所需参数
);
/// <summary>
/// 用户自定义函数列表
/// </summary>
public struct FunctionList
{
private Function[] Func; //函数执行体的代理
private string[] FuncName; //函数名
private int[] ParamCount; //参数个数
private int _Count; //列表中已使用的代理的个数
/// <summary>
/// 获取自定义函数个数
/// </summary>
public int Count{get{return _Count;}}
/// <summary>
/// 获取允许的自定义函数最大个数
/// </summary>
public int Length{ get{return FuncName.Length;} }
/// <summary>
/// 初始化
/// </summary>
/// <param name="size">自定义函数最大个数</param>
public FunctionList(int size)
{
Func=new Function[size];
FuncName=new string[size];
ParamCount=new int[size];
for(int i=0;i<FuncName.Length;i++)
{
Func[i]=null;
FuncName[i]="";
ParamCount[i]=0;
}
_Count=0;
}
/// <summary>
/// 获取指定函数别名在列表中的索引(位置)
/// </summary>
/// <param name="funcName">函数别名</param>
/// <returns>不存在返回-1, 否则返回>=0的整数</returns>
public int IndexOf(string funcName)
{
if(funcName==null || funcName=="")
return -1;
for(int i=0;i<_Count-1;i++)
if(FuncName[i]==funcName)
return i;
return -1;
}
/// <summary>
/// 设置指定函数别名的执行体代理
/// </summary>
/// <param name="funcName">表达式中对应的函数名</param>
/// <param name="paramCount">参数个数</param>
/// <param name="func">函数体</param>
public void Add(string funcName, int paramCount, Function func)
{
int index=IndexOf(funcName);
if(index==-1)
{
if(_Count<this.Length)
{
FuncName[_Count]=funcName;
Func[_Count]=func;
ParamCount[_Count]=paramCount;
_Count++;
}
else
throw new Exception("添加函数出错, 列表已满");
}
else
{
Func[index]=func;
ParamCount[index]=paramCount;
}
}
/// <summary>
/// 获取指定函数的执行体代理
/// </summary>
public Function this[string func]
{
get
{
int index=IndexOf(func);
if(index==-1)
return null;
else
return Func[index];
}
}
/// <summary>
/// 获取自定义函数的参数个数
/// </summary>
/// <param name="func">函数名</param>
/// <returns></returns>
public int ParameterCount(string func)
{
int index=IndexOf(func);
if(index==-1)
return -1;
else
return ParamCount[index];
}
}
#endregion
public string Expression; //要计算的表在式
private string[] Word;
private ValStack Val;
private SignStack Sign;
/// <summary>
/// 变量列表
/// </summary>
public Variable Var;
/// <summary>
/// 函数执行体列表
/// </summary>
public FunctionList Func;
/// <summary>
/// 以本实例表达式作为自定义函数
/// </summary>
public Function DefFunction;
/// <summary>
/// 初始化
/// </summary>
/// <param name="expression">要计算的表达式</param>
public Evaluator(string expression)
{
Val = new ValStack();
Sign = new SignStack();
Var = new Variable(20);
Func = new FunctionList(50);
FunctionLib.AssignFunctionLib(ref Func);
DefFunction = new Function(this.function);
this.Expression=expression;
}
public Evaluator() : this("")
{
}
/// <summary>
/// 获取表达式中的变量
/// </summary>
/// <returns></returns>
public string[] GetVariables()
{
ArrayList wordList = new ArrayList();
string[] words=WordAnalysis.Analysis(Expression);
for(int i = 0; i<words.Length; i++)
{
if ( Char.IsLetter(words[i][0]) && !IsFunc(words[i]))
{
if(wordList.Contains(words[i]) == false)
wordList.Add(words[i]);
}
}
string[] vars = new string[wordList.Count];
for(int i=0; i < vars.Length; i++)
{
vars[i] = (string) wordList[i];
}
return vars;
}
/// <summary>
/// 对每次更改计算表达式时进行类初始化
/// </summary>
private void InitExpression()
{
Word = WordAnalysis.Analysis(Expression);
}
/// <summary>
/// DEBGU...???....delegate
/// </summary>
/// <param name="pa"></param>
/// <returns></returns>
public double function(params double[] pa)
{
return this.Calculate();
}
int Priority(string sign) //符号优先级
{
if(sign=="(")
return 32767;
else if(sign==")")
return -32767;
else if(sign=="*" || sign=="/")
return 8;
else if(sign=="+" || sign=="-")
return 4;
else if(sign==",")
return 2;
else
{
if(IsFunc(sign))
return 16;
else
return 0;
}
}
bool IsNum(string word) //是数字
{
for(int i=0;i<word.Length;i++)
{
if(word[i]!='.' && "0123456789".IndexOf(word[i])==-1)
return false;
}
return true;
}
bool IsVar(string word) //是变量
{
return Var.IndexOf(word)!=-1;
}
bool IsFunc(string word) //是自定义函数
{
return Func.IndexOf(word) != -1;
}
bool IsSign(string word) //是符号
{
string[] sign=WordAnalysis.Seperator; //new string[]{"+", "-", "*", "/", ",", "(", ")"};
if(word.Trim()=="")
return false;
for(int i=0; i<sign.Length;i++)
if(word==sign[i])
return true;
return false;
}
bool IsOtherWord(string word) //不是数字, 变量, 函数名, 符号 的单词
{
return !(IsNum(word) || IsVar(word) || IsFunc(word) || IsSign(word));
}
/// <summary>
/// 计算sign(+-*/等)的a,b值
/// </summary>
/// <param name="sign">符号</param>
/// <param name="a">每一个值(符号左边的值)</param>
/// <param name="b">每二个值(符号右边的值)</param>
/// <returns></returns>
double Compute(string sign, double a, double b)
{
double ret=0;
switch(sign)
{
case "+":
ret=a+b;
break;
case "-":
ret=a-b;
break;
case "*":
ret = a*b; //可能会产生溢出错
break;
case "/":
ret=a/b; //注意,a为0会产生0除错异常, 此处不处理
break;
default:
if(IsFunc(sign))
{
double[] parameter=new double[Func.ParameterCount(sign)];
for(int i=parameter.Length-1;i>=0;i--)
parameter[i]=Val.Pop();
Function func=Func[sign];
ret=func(parameter);
}
else
throw new Exception("无法识别的符号: "+sign);
break;
}
return ret;
}
/// <summary>
/// 计算表达式的值
/// UNDONE: 用户自定义函数有错...
/// </summary>
/// <returns></returns>
public double Calculate()
{
InitExpression();
int cur; //当前计算到的单词在Word数组中的索引(位置)
for(cur=0;cur<Word.Length;cur++) //循环读单词,计算表达式.
{
if(IsNum(Word[cur]))
{
Val.Push(Convert.ToSingle(Word[cur]));
}
else if( Word[cur]=="(" )
{
Sign.Push(Word[cur]);
}
else if(Word[cur]==",")
{
}
else if(IsFunc(Word[cur]))
{
Sign.Push(Word[cur]);
}
else if(IsVar(Word[cur]))
{
Val.Push(Var[Word[cur]]);
}
else if(IsSign(Word[cur])) //可能是以下单词: "+-*/,)"
{
while( Priority(Sign.Peek()) >= Priority(Word[cur]) )
{
if( Sign.Peek()=="(" )
{
if(Word[cur]==")")
Sign.Pop();
break;
}
else if(IsFunc(Sign.Peek())) //计算自定义函数
{
// double[] parameter=new double[Func.ParameterCount(Sign.Peek())];
// for(int i=parameter.Length-1;i>=0;i--)
// {
// parameter[i]=Val.Pop();
// }
Val.Push( Compute(Sign.Peek() , 0, 0) );
}
else //只计算有 "+-*/" 的情况
{
double b=Val.Pop(), a=Val.Pop();
Val.Push(Compute(Sign.Peek(), a, b));
}
Sign.Pop(); //将当前栈顶已计算过的符号舍弃
}
if(Word[cur]!=")" && Word[cur]!=",")
Sign.Push(Word[cur]);
}
else
throw new Exception("表达式包含非法字符: "+Word[cur]);
}
while(Sign.Count>0) //还有未计算完的符号,剩下的符号一定是栈底的优先级最低, 栈顶的最高
{
string curSign=Sign.Pop();
if(curSign=="(" || curSign==",")
continue;
else if (IsFunc(curSign))
Val.Push(Compute(curSign,0,0));
else if(IsSign(curSign))
{
double b=Val.Pop(), a=Val.Pop();
Val.Push(Compute(curSign, a, b));
}
}
return Val.Pop(); //最终数值栈只剩一个数值,这就是最终结果.
}
}
public class FunctionLib
{
private FunctionLib()
{
}
/// <summary>
/// 表达式默认支持的函数
/// </summary>
/// <param name="list"></param>
public static void AssignFunctionLib(ref Evaluator.FunctionList list) // 不加ref 修饰 无法使得修改后的list被返回
{
list.Add("Pow", 2, new Evaluator.Function(Pow));
list.Add("Exp", 1, new Evaluator.Function(Exp));
list.Add("Sqrt", 1, new Evaluator.Function(Sqrt));
list.Add("Log", 2, new Evaluator.Function(Log));
list.Add("Abs", 1, new Evaluator.Function(Abs));
list.Add("Max", 2, new Evaluator.Function(Max));
list.Add("Min", 2, new Evaluator.Function(Min));
}
public static double Pow(params double[] p)
{
return Math.Pow(p[0], p[1]);
}
public static double Sqrt(params double[] p)
{
return Math.Sqrt(p[0]);
}
public static double Exp(params double[] p)
{
return Math.Exp(p[0]);
}
public static double Log(params double[] p)
{
return Math.Log(p[0], p[1]);
}
public static double Abs(params double[] p)
{
return Math.Abs(p[0]);
}
public static double Max(params double[] p)
{
return Math.Max(p[0], p[1]);
}
public static double Min(params double[] p)
{
return Math.Min(p[0], p[1]);
}
}
}
posted on 2006-01-17 09:31
Rivers Zhao 阅读(614)
评论(4) 编辑 收藏 网摘