正文

C#编写的字符串算术表达式计算类2008-07-26 15:57:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/iamben250/37116.html

分享到:

下面是文件的内容,将其全部复制到c#语言下的一个类中即可按上文要求的使用。

///<author>Emad Barsoum</author>
///<email>ebarsoum@msn.com</email>
///<date>March 23, 2002</date>
///<copyright>
///This code is Copyright to Emad Barsoum, it can be used or changed for free without removing the header
///information which is the author name, email and date or refer to this information if any change made.
///</copyright>
///<summary>
///This class <c>Function</c> use the transformation from infix notation to postfix notation to evalute most
///Mathematic expression, it support most operators (+,-,*,/,%,^), functions from 0 to any number of parameters
///and also a user defined function by using delegate, also it support variables in the expression, it will
///generate a symbol table that can be updated at run time.
///</summary>

using System;
using System.Collections;

namespace EB.Math
{
 /// <summary>
 /// </summary>
 ///
  public enum Type{Variable,Value,UnaryOperator,Operator,Function,Result,Bracket,Comma,Error}
  public struct Symbol
  {
    public string m_name;
    public double m_value;
    public Type m_type;
    public override string ToString()
    {
      return m_name;
    }
  }
  public delegate Symbol EvaluateFunctionDelegate(string name, params Object[] args);
 public class Function
 {
    public double Result
    {
      get
      {
        return m_result;
      }
    }

    public ArrayList Equation
    {
      get
      {
        return (ArrayList)m_equation.Clone();
      }
    }
    public ArrayList Postfix
    {
      get
      {
        return (ArrayList)m_postfix.Clone();
      }
    }

    public EvaluateFunctionDelegate DefaultFunctionEvaluation
    {
      set
      {
        m_defaultFunctionEvaluation = value;
      }
    }

    public bool Error
    {
      get
      {
        return m_bError;
      }
    }

    public string ErrorDescription
    {
      get
      {
        return m_sErrorDescription;
      }
    }

 public ArrayList Variables
 {
   get
   {
    ArrayList var = new ArrayList();
    foreach(Symbol sym in m_equation)
    {
      if((sym.m_type == Type.Variable) && (!var.Contains(sym)))
         var.Add(sym);
    }
    return var;
   }
   set
   {
      foreach(Symbol sym in value)
      {
        for(int i=0;i<m_postfix.Count;i++)
        {
          if((sym.m_name == ((Symbol)m_postfix[i]).m_name) && (((Symbol)m_postfix[i]).m_type == Type.Variable))
          {
            Symbol sym1 = (Symbol)m_postfix[i];
            sym1.m_value = sym.m_value;
            m_postfix[i] = sym1;
          }
        }
      }
   }
 }

 public Function()
 {}

    public void Parse(string equation)
    {
      int state = 1;
      string temp = "";
      Symbol ctSymbol;

      m_bError = false;
      m_sErrorDescription = "None";

      m_equation.Clear();
      m_postfix.Clear();

      int nPos = 0;
      //-- Remove all white spaces from the equation string --
      equation = equation.Trim();
      while((nPos=equation.IndexOf(' ')) != -1)
        equation = equation.Remove(nPos,1);

      for(int i=0;i<equation.Length;i++)
      {
        switch(state)
        {
          case 1:
            if(Char.IsNumber(equation[i]))
            {
              state = 2;
              temp += equation[i];
            }
            else if(Char.IsLetter(equation[i]))
            {
              state = 3;
              temp += equation[i];
            }
            else
            {
              ctSymbol.m_name = equation[i].ToString();
              ctSymbol.m_value = 0;
              switch(ctSymbol.m_name)
              {
                case ",":
                  ctSymbol.m_type = Type.Comma;
                  break;
                case "(":
                case ")":
                case "[":
                case "]":
                case "{":
                case "}":
                  ctSymbol.m_type = Type.Bracket;
                  break;
                default:
                  if(m_equation.Count == 0)
                    ctSymbol.m_type = Type.UnaryOperator;
                  else if((((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Value) || (((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Variable)
                    || (((Symbol)m_equation[m_equation.Count-1]).m_name == ")") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "]") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "}"))
                    ctSymbol.m_type = Type.Operator;
                  else
                    ctSymbol.m_type = Type.UnaryOperator;
                  break;
              }
              m_equation.Add(ctSymbol);
            }  
            break;
          case 2:
            if((Char.IsNumber(equation[i])) || (equation[i] == '.'))
              temp += equation[i];
            else if(!Char.IsLetter(equation[i]))
            {
              state = 1;
              ctSymbol.m_name = temp;
              ctSymbol.m_value = Double.Parse(temp);
              ctSymbol.m_type = Type.Value;
              m_equation.Add(ctSymbol);
              ctSymbol.m_name = equation[i].ToString();
              ctSymbol.m_value = 0;
              switch(ctSymbol.m_name)
              {
                case ",":
                  ctSymbol.m_type = Type.Comma;
                  break;
                case "(":
                case ")":
                case "[":
                case "]":
                case "{":
                case "}":
                  ctSymbol.m_type = Type.Bracket;
                  break;
                default:
                  if(m_equation.Count == 0)
                    ctSymbol.m_type = Type.UnaryOperator;
                  else if((((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Value) || (((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Variable)
                    || (((Symbol)m_equation[m_equation.Count-1]).m_name == ")") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "]") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "}"))
                    ctSymbol.m_type = Type.Operator;
                  else
                    ctSymbol.m_type = Type.UnaryOperator;
                  break;
              }
              m_equation.Add(ctSymbol);
              temp = "";
            }
            break;
          case 3:
            if(Char.IsLetterOrDigit(equation[i]))
              temp += equation[i];
            else
            {
              state = 1;
              ctSymbol.m_name = temp;
              ctSymbol.m_value = 0;
              if(equation[i] == '(')
                ctSymbol.m_type = Type.Function;
              else
              {
                if(ctSymbol.m_name == "pi")
                  ctSymbol.m_value = System.Math.PI;
                else if(ctSymbol.m_name == "e")
                  ctSymbol.m_value = System.Math.E;
                ctSymbol.m_type = Type.Variable;
              }
              m_equation.Add(ctSymbol);
              ctSymbol.m_name = equation[i].ToString();
              ctSymbol.m_value = 0;
              switch(ctSymbol.m_name)
              {
                case ",":
                  ctSymbol.m_type = Type.Comma;
                  break;
                case "(":
                case ")":
                case "[":
                case "]":
                case "{":
                case "}":
                  ctSymbol.m_type = Type.Bracket;
                  break;
                default:
                  if(m_equation.Count == 0)
                    ctSymbol.m_type = Type.UnaryOperator;
                  else if((((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Value) || (((Symbol)m_equation[m_equation.Count-1]).m_type == Type.Variable)
                    || (((Symbol)m_equation[m_equation.Count-1]).m_name == ")") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "]") || (((Symbol)m_equation[m_equation.Count-1]).m_name == "}"))
                    ctSymbol.m_type = Type.Operator;
                  else
                    ctSymbol.m_type = Type.UnaryOperator;
                  break;
              }
              m_equation.Add(ctSymbol);
              temp = "";
            }
            break;
        }
      }
      if(temp != "")
      {
        ctSymbol.m_name = temp;       
        if(state == 2)
        {
          ctSymbol.m_value = Double.Parse(temp);
            ctSymbol.m_type = Type.Value;
        }
        else
        {
          if(ctSymbol.m_name == "pi")
            ctSymbol.m_value = System.Math.PI;
          else if(ctSymbol.m_name == "e")
            ctSymbol.m_value = System.Math.E;
          else
            ctSymbol.m_value = 0;
          ctSymbol.m_type = Type.Variable;
        }
        m_equation.Add(ctSymbol);
      }
    }
 
    public void Infix2Postfix()
    {
      Symbol tpSym;
      Stack tpStack = new Stack();
      foreach(Symbol sym in m_equation)
      {
        if((sym.m_type == Type.Value) || (sym.m_type == Type.Variable))
          m_postfix.Add(sym);
        else if((sym.m_name == "(") || (sym.m_name == "[") || (sym.m_name == "{"))
          tpStack.Push(sym);
        else if((sym.m_name == ")") || (sym.m_name == "]") || (sym.m_name == "}"))
        {
          if(tpStack.Count > 0)
          {
            tpSym = (Symbol)tpStack.Pop();
            while((tpSym.m_name != "(") && (tpSym.m_name != "[") && (tpSym.m_name != "{"))
            {
              m_postfix.Add(tpSym);
              tpSym = (Symbol)tpStack.Pop();
            }
          }
        }
        else if(sym.m_type == Type.UnaryOperator)
        {
          tpStack.Push(sym);
        }
        else
        {
          if(tpStack.Count > 0)
          {
            tpSym = (Symbol)tpStack.Pop();
            while((tpStack.Count != 0) && ((tpSym.m_type == Type.UnaryOperator) || (tpSym.m_type == Type.Operator) || (tpSym.m_type == Type.Function) || (tpSym.m_type == Type.Comma)) && (Precedence(tpSym) >= Precedence(sym)))
            {
              m_postfix.Add(tpSym);
              tpSym = (Symbol)tpStack.Pop();  
            }
            if(((tpSym.m_type == Type.UnaryOperator) || (tpSym.m_type == Type.Operator) || (tpSym.m_type == Type.Function) || (tpSym.m_type == Type.Comma)) && (Precedence(tpSym) >= Precedence(sym)))
              m_postfix.Add(tpSym);
            else
              tpStack.Push(tpSym);
          }
          tpStack.Push(sym);
        }
      }
      while(tpStack.Count > 0)
      {
        tpSym = (Symbol)tpStack.Pop();
        m_postfix.Add(tpSym);
      }
    }

    public void EvaluatePostfix()
    {
      Symbol tpSym1, tpSym2, tpResult;
      Stack tpStack = new Stack();
      ArrayList fnParam = new ArrayList();
      m_bError = false;
      foreach(Symbol sym in m_postfix)
      {
        if((sym.m_type == Type.Value) || (sym.m_type == Type.Variable) || (sym.m_type == Type.Result))
          tpStack.Push(sym);
        else if(sym.m_type == Type.UnaryOperator)
        {
          tpSym1 = (Symbol)tpStack.Pop();
          tpResult = Evaluate(sym, tpSym1);
          if(tpResult.m_type == Type.Error)
          {
            m_bError = true;
            m_sErrorDescription = tpResult.m_name;
            return;
          }
          tpStack.Push(tpResult);
        }
        else if(sym.m_type == Type.Operator)
        {
          tpSym1 = (Symbol)tpStack.Pop();
          tpSym2 = (Symbol)tpStack.Pop();
          tpResult = Evaluate(tpSym2, sym, tpSym1);
          if(tpResult.m_type == Type.Error)
          {
            m_bError = true;
            m_sErrorDescription = tpResult.m_name;
            return;
          }
          tpStack.Push(tpResult);
        }
        else if(sym.m_type == Type.Comma)
        {
          tpStack.Push(sym);
        }
        else if(sym.m_type == Type.Function)
        {
          fnParam.Clear();
          tpSym1 = (Symbol)tpStack.Pop();
          if((tpSym1.m_type == Type.Value) || (tpSym1.m_type == Type.Variable) || (tpSym1.m_type == Type.Result))
          {
            tpResult = EvaluateFunction(sym.m_name,tpSym1);
            if(tpResult.m_type == Type.Error)
            {
              m_bError = true;
              m_sErrorDescription = tpResult.m_name;
              return;
            }
            tpStack.Push(tpResult);
          }
          else if(tpSym1.m_type == Type.Comma)
          {
            while(tpSym1.m_type == Type.Comma)
            {
              tpSym1 = (Symbol)tpStack.Pop();
              fnParam.Add(tpSym1);
              tpSym1 = (Symbol)tpStack.Pop();
            }
            fnParam.Add(tpSym1);
            tpResult = EvaluateFunction(sym.m_name,fnParam.ToArray());
            if(tpResult.m_type == Type.Error)
            {
              m_bError = true;
              m_sErrorDescription = tpResult.m_name;
              return;
            }
            tpStack.Push(tpResult);
          }
          else
          {
            tpStack.Push(tpSym1);
            tpResult = EvaluateFunction(sym.m_name);
            if(tpResult.m_type == Type.Error)
            {
              m_bError = true;
              m_sErrorDescription = tpResult.m_name;
              return;
            }
            tpStack.Push(tpResult);
          }
        }      
      }
      if(tpStack.Count == 1)
      {
        tpResult = (Symbol)tpStack.Pop();
        m_result = tpResult.m_value;
      }
    }

    protected int Precedence(Symbol sym)
    {
      switch(sym.m_type)
      {
        case Type.Bracket:
          return 7;
        case Type.Function:
          return 5;
        case Type.UnaryOperator:
          return 4;
        case Type.Comma:
          return 0;
      }
      switch(sym.m_name)
      {
        case "^":
          return 3;
        case "/":
        case "*":
        case "%":
          return 2;
        case "+":
        case "-":
          return 1;
      }
      return -1;
    }

    protected Symbol Evaluate(Symbol opr, Symbol sym1)
    {
      Symbol result;
      result.m_name = opr.m_name + sym1.m_name;
      result.m_type = Type.Result;
      result.m_value = 0;
      switch(opr.m_name)
      {
        case "+":
          result.m_value = sym1.m_value;;
          break;
        case "-":
          result.m_value = -1 * sym1.m_value;
          break;
        default:
          result.m_type = Type.Error;
          result.m_name = "Undefine unary operator: " + opr.m_name + ".";
          break;
      }
      return result;
    }

    protected Symbol Evaluate(Symbol sym1, Symbol opr, Symbol sym2)
    {
      Symbol result;
      result.m_name = sym1.m_name + opr.m_name + sym2.m_name;
      result.m_type = Type.Result;
      result.m_value = 0;
      switch(opr.m_name)
      {
        case "^":
          result.m_value = System.Math.Pow(sym1.m_value,sym2.m_value);
          break;
        case "/":
        {
          if(sym2.m_value != 0)
            result.m_value = sym1.m_value / sym2.m_value;
          else
          {
            result.m_name = "Divide by Zero.";
            result.m_type = Type.Error;
          }
          break;
        }
        case "*":
          result.m_value = sym1.m_value * sym2.m_value;
          break;
        case "%":
          result.m_value = sym1.m_value % sym2.m_value;
          break;
        case "+":
          result.m_value = sym1.m_value + sym2.m_value;
          break;
        case "-":
          result.m_value = sym1.m_value - sym2.m_value;
          break;
        default:
          result.m_type = Type.Error;
          result.m_name = "Undefine operator: " + opr.m_name + ".";
          break;
      }
      return result;
    }

    protected Symbol EvaluateFunction(string name, params Object[] args)
    {
      Symbol result;
      result.m_name = "";
      result.m_type = Type.Result;
      result.m_value = 0;
      switch(name)
      {
        case "cos":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Cos(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "sin":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Sin(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "tan":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Tan(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "cosh":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Cosh(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "sinh":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Sinh(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "tanh":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Tanh(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "log":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Log10(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "ln":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Log(((Symbol)args[0]).m_value,2);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "logn":
          if(args.Length == 2)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + "'" + ((Symbol)args[1]).m_value.ToString() + ")";
            result.m_value = System.Math.Log(((Symbol)args[0]).m_value,((Symbol)args[1]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "sqrt":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Sqrt(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "abs":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Abs(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "acos":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Acos(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "asin":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Asin(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "atan":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Atan(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        case "exp":
          if(args.Length == 1)
          {
            result.m_name = name + "(" + ((Symbol)args[0]).m_value.ToString() + ")";
            result.m_value = System.Math.Exp(((Symbol)args[0]).m_value);
          }
          else
          {
            result.m_name = "Invalid number of parameters in: "+ name +".";
            result.m_type = Type.Error;
          }
          break;
        default:
          if(m_defaultFunctionEvaluation != null)
            result = m_defaultFunctionEvaluation(name,args);
          else
          {
            result.m_name = "Function: "+ name +", not found.";
            result.m_type = Type.Error;
          }
          break;
      }
      return result;
    }
 
    protected bool m_bError = false;
    protected string m_sErrorDescription = "None";
    protected double m_result = 0;
    protected ArrayList m_equation = new ArrayList();
    protected ArrayList m_postfix = new ArrayList();
    protected EvaluateFunctionDelegate m_defaultFunctionEvaluation;
  }
}

阅读(1653) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册