随笔 - 3  文章 - 0 评论 - 4 trackbacks - 0
<2008年10月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

与我联系

搜索

 

常用链接

留言簿

我参加的小组

我参与的团队

随笔分类

随笔档案(3)

相册

收藏夹(11)

积分与排名

  • 积分 - 5627
  • 排名 - 5253

最新评论

阅读排行榜

评论排行榜

以前在一个项目里面用到东西, 我在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)  编辑 收藏 网摘

FeedBack:
#1楼  2006-02-22 19:44 U2USoft      
建议用CodeDom对象或者用VSA吧,超级方便。
  回复  引用  查看    
#2楼  2006-07-25 10:43 Ivony...      
不错不错,用CodeDom或者VSA当然是方便,久而久之自己就成了傻瓜。学习编译器的原理对自己非常有帮助,支持搂主。况且效率也很高……。
  回复  引用  查看    
#3楼  2006-08-17 09:57 ocool [未注册用户]
但是最后一个函数不能被支持,总是提示“表达式包含非法字符: ……”。
  回复  引用    
为什么不用Stack类呢
  回复  引用    




标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: