.net表达式计算器(中缀表达式转后缀表达式,支持20多个数学函数,支持函数嵌套,免费共享~)...

最近在网上查了一下表达工计算器的类库,发现Java版本的有一个比较成熟的叫W3EVal,好像是一个IBM工程师写的,.net就很少了(可能是我了解不够多),但投机取巧的实现思路有很多,比如:
  (1)将Javasript中代码编译成.net类库,利用Javascript中的eval函数来实现;
  (2)利用ScriptControl执行JavaScript脚本实现;
  (3)利用DataTable的计算功能实现简单计算;
  (4)利用.net动态编译功能来实现等
  这些方法在csdn的坛里有讨论,请见:http://topic.csdn.net/u/20070301/13/c8c33bd1-f146-4b44-9882-aab6d430f724.html

  心想既然还没有成熟的.net类库,何不自己做一个呢,其实并不难,只要稍有点耐心调试一下就好了。于是参考一编中缀表达式转后缀表达式的论文,很快写了一个,发现效果不错,所以发出来跟大家共享,希望对大家有用。

  中缀表达式转后缀表达式的步骤为:
  1.新建一个Stack栈,用来存放运算符
  2.新建一个post栈,用来存放最后的后缀表达式
  3.从左到右扫描中缀表达式:
    (1)若读到的是操作数,直接存入post栈,以#作为数字的结束
    (2)若读到的是(,则直接存入stack栈
    (3)若读到的是),则将stack栈中(前的所有运算符出栈,存入post栈
    (4)若读到的是其它运算符,则将该运算符和stack栈顶运算符作比较:若高于或等于栈顶运算符,则直接存入stack栈,否则将栈顶运算符(所有优先级高于读到的运算符的,不包括括号)出栈,存入post栈。最后将读到的运算符入栈。
  4.当扫描完后,stack栈中还在运算符时,则将所有的运算符出栈,存入post栈
             

  计算后缀表达式的值的步骤为:
  1.初始化一个空堆栈
  2.从左到右读入后缀表达式
  3.如果字符是一个操作数,把它压入堆栈。
  4.如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
  5.到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。

  

  类库的名称就名为NEval ,感觉还比较健壮,速度很快,支持20个数学函数,很容易扩充。目前还没有表达式合法性检查的功能,有兴趣的朋友可以扩充一下,先谢谢。

  代码如下:

ExpandedBlockStart.gif 代码
///   <summary>
    
///  表达式计算类。支持数学函数,支持函数嵌套
    
///  作者watsonyin
    
///  开发日期:2010年10月 版本1.0
    
///   </summary>
     public   class  NEval
    {
        
public  NEval()
        {

        }

        
public   double  Eval( string  expr)
        {
            
try
            {
                
string  tmpexpr  =  expr.ToLower().Trim().Replace( "   " string .Empty);
                
return  Calc_Internal(tmpexpr);
            }
            
catch  (ExpressionException eex)
            {
                
throw  eex;
            }
            
catch
            {
                
throw   new  Exception( " 表达式错误 " );
            }
        }

        
private  Random m_Random  =   null ;
        
private   double  Calc_Internal( string  expr)
        {
            
/*
             * 1.    初始化一个空堆栈 
             * 2.    从左到右读入后缀表达式 
             * 3.    如果字符是一个操作数,把它压入堆栈。 
             * 4.    如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。 
             * 5.    到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。
            
*/

            Stack post2  =  ConvertExprBack(expr);
            Stack post  =   new  Stack();
            
while  (post2.Count  >   0 )
                post.Push(post2.Pop());

            Stack stack  =   new  Stack();
            
while  (post.Count  >   0 )
            {
                
string  tmpstr  =  post.Pop().ToString();
                
char  c  =  tmpstr[ 0 ];
                LetterType lt  =  JudgeLetterType(tmpstr);
                
if  (lt  ==  LetterType.Number)
                {
                    stack.Push(tmpstr);
                }
                
else   if  (lt  ==  LetterType.SimpleOperator)
                {
                    
double  d1  =   double .Parse(stack.Pop().ToString());
                    
double  d2  =   double .Parse(stack.Pop().ToString());
                    
double  r  =   0 ;
                    
if  (c  ==   ' + ' )
                        r  =  d2  +  d1;
                    
else   if  (c  ==   ' - ' )
                        r  =  d2  -  d1;
                    
else   if  (c  ==   ' * ' )
                        r  =  d2  *  d1;
                    
else   if  (c  ==   ' / ' )
                        r  =  d2  /  d1;
                    
else   if  (c  ==   ' ^ ' )
                        r  =  Math.Pow(d2, d1);
                    
else
                        
throw   new  Exception( " 不支持操作符: "   +  c.ToString());
                    stack.Push(r);
                }
                
else   if  (lt  ==  LetterType.Function)   // 如果是函数
                {
                    
string [] p;
                    
double  d  =   0 ;
                    
double  d1  =   0 ;
                    
double  d2  =   0 ;
                    
int  tmpos  =  tmpstr.IndexOf( ' ( ' );
                    
string  funcName  =  tmpstr.Substring( 0 , tmpos);
                    
switch  (funcName)
                    {
                        
case   " asin " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Asin(d).ToString());
                            
break ;
                        
case   " acos " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Acos(d).ToString());
                            
break ;
                        
case   " atan " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Atan(d).ToString());
                            
break ;
                        
case   " acot " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(( 1   /  Math.Atan(d)).ToString());
                            
break ;
                        
case   " sin " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Sin(d).ToString());
                            
break ;
                        
case   " cos " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Cos(d).ToString());
                            
break ;
                        
case   " tan " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Tan(d).ToString());
                            
break ;
                        
case   " cot " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(( 1   /  Math.Tan(d)).ToString());
                            
break ;
                        
case   " log " :
                            SplitFuncStr(tmpstr,  2 out  p);
                            d1  =   double .Parse(p[ 0 ]);
                            d2  =   double .Parse(p[ 1 ]);
                            stack.Push(Math.Log(d1, d2).ToString());
                            
break ;
                        
case   " ln " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Log(d, Math.E).ToString());
                            
break ;
                        
case   " abs " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Abs(d).ToString());
                            
break ;
                        
case   " round " :
                            SplitFuncStr(tmpstr,  2 out  p);
                            d1  =   double .Parse(p[ 0 ]);
                            d2  =   double .Parse(p[ 1 ]);
                            stack.Push(Math.Round(d1, ( int )d2).ToString());
                            
break ;
                        
case   " int " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(( int )d);
                            
break ;
                        
case   " trunc " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Truncate(d).ToString());
                            
break ;
                        
case   " floor " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Floor(d).ToString());
                            
break ;
                        
case   " ceil " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Ceiling(d).ToString());
                            
break ;
                        
case   " random " :
                            
if  (m_Random  ==   null )
                                m_Random  =   new  Random();
                            d  =  m_Random.NextDouble();
                            stack.Push(d.ToString());
                            
break ;
                        
case   " exp " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Exp(d).ToString());
                            
break ;
                        
case   " pow " :
                            SplitFuncStr(tmpstr,  2 out  p);
                            d1  =   double .Parse(p[ 0 ]);
                            d2  =   double .Parse(p[ 1 ]);
                            stack.Push(Math.Pow(d1, d2).ToString());
                            
break ;
                        
case   " sqrt " :
                            SplitFuncStr(tmpstr,  1 out  p);
                            d  =   double .Parse(p[ 0 ]);
                            stack.Push(Math.Sqrt(d).ToString());
                            
break ;
                        
default :
                            
throw   new  Exception( " 未定义的函数: "   +  funcName);

                    }

                }
            }
            
object  obj  =  stack.Pop();
            
return   double .Parse(obj.ToString());
        }

        
///   <summary>
        
///  将函数括号内的字符串进行分割,获得参数列表,如果参数是嵌套的函数,用递归法计算得到它的值
        
///   </summary>
        
///   <param name="funcstr"></param>
        
///   <param name="paramCount"></param>
        
///   <param name="parameters"></param>
         private   void  SplitFuncStr( string  funcstr,  int  paramCount,  out   string [] parameters)
        {
            parameters  =   new   string [paramCount];
            
int  tmpPos  =  funcstr.IndexOf( ' ( ' 0 );
            
string  str  =  funcstr.Substring(tmpPos  +   1 , funcstr.Length  -  tmpPos  -   2 );
            
if  (paramCount  ==   1 )
            {
                parameters[ 0 =  str;
            }
            
else
            {
                
int  cpnum  =   0 ;
                
int  startPos  =   0 ;
                
int  paramIndex  =   0 ;
                
for  ( int  i  =   0 ; i  <=  str.Length  -   1 ; i ++ )
                {
                    
if  (str[i]  ==   ' ( ' )
                        cpnum ++ ;
                    
else   if  (str[i]  ==   ' ) ' )
                        cpnum -- ;
                    
else   if  (str[i]  ==   ' , ' )
                    {
                        
if  (cpnum  ==   0 )
                        {
                            
string  tmpstr  =  str.Substring(startPos, i  -  startPos);
                            parameters[paramIndex]  =  tmpstr;
                            paramIndex ++ ;
                            startPos  =  i  +   1 ;
                        }
                    }
                }
                
if  (startPos  <  str.Length)
                {
                    
string  tmpstr  =  str.Substring(startPos);
                    parameters[paramIndex]  =  tmpstr;
                }
            }

            
// 如果参数是函数, 进一步采用递归的方法生成函数值
             for  ( int  i  =   0 ; i  <=  paramCount  -   1 ; i ++ )
            {
                
double  d;
                
if  ( ! double .TryParse(parameters[i],  out  d))
                {
                    NEval calc  =   new  NEval();
                    d  =  calc.Eval(parameters[i]);
                    parameters[i]  =  d.ToString();
                }
            }
        }


        
///   <summary>
        
///  将中缀表达式转为后缀表达式
        
///   </summary>
        
///   <param name="expr"></param>
        
///   <returns></returns>
         private  Stack ConvertExprBack( string  expr)
        {
            
/*
             * 新建一个Stack栈,用来存放运算符
             * 新建一个post栈,用来存放最后的后缀表达式
             * 从左到右扫描中缀表达式:
             * 1.若读到的是操作数,直接存入post栈,以#作为数字的结束
             * 2、若读到的是(,则直接存入stack栈
             * 3.若读到的是),则将stack栈中(前的所有运算符出栈,存入post栈
             * 4 若读到的是其它运算符,则将该运算符和stack栈顶运算符作比较:若高于或等于栈顶运算符, 则直接存入stack栈,
             * 否则将栈顶运算符(所有优先级高于读到的运算符的,不包括括号)出栈,存入post栈。最后将读到的运算符入栈
             * 当扫描完后,stack栈中还在运算符时,则将所有的运算符出栈,存入post栈
             *  */


            Stack post  =   new  Stack();
            Stack stack  =   new  Stack();
            
string  tmpstr;
            
int  pos;
            
for  ( int  i  =   0 ; i  <=  expr.Length  -   1 ; i ++ )
            {
                
char  c  =  expr[i];
                LetterType lt  =  JudgeLetterType(c, expr, i);

                
if  (lt  ==  LetterType.Number)   // 操作数
                {
                    GetCompleteNumber(expr, i,  out  tmpstr,  out  pos);
                    post.Push(tmpstr);
                    i  =  pos; //  +1;
                }
                
else   if  (lt  ==  LetterType.OpeningParenthesis)  // 左括号(
                {
                    stack.Push(c);
                }
                
else   if  (lt  ==  LetterType.ClosingParenthesis)  // 右括号)
                {
                    
while  (stack.Count  >   0 )
                    {
                        
if  (stack.Peek().ToString()  ==   " ( " )
                        {
                            stack.Pop();
                            
break ;
                        }
                        
else
                            post.Push(stack.Pop());
                    }
                }
                
else   if  (lt  ==  LetterType.SimpleOperator)   // 其它运算符
                {
                    
if  (stack.Count  ==   0 )
                        stack.Push(c);
                    
else
                    {

                        
char  tmpop  =  ( char )stack.Peek();
                        
if  (tmpop  ==   ' ( ' )
                        {
                            stack.Push(c);
                        }
                        
else
                        {
                            
if  (GetPriority(c)  >=  GetPriority(tmpop))
                            {
                                stack.Push(c);
                            }
                            
else
                            {
                                
while  (stack.Count  >   0 )
                                {
                                    
object  tmpobj  =  stack.Peek();
                                    
if  (GetPriority(( char )tmpobj)  >  GetPriority(c))
                                    {
                                        
if  (tmpobj.ToString()  !=   " ( " )
                                            post.Push(stack.Pop());
                                        
else
                                            
break ;
                                    }
                                    
else
                                        
break ;
                                }
                                stack.Push(c);
                            }
                        }


                    }
                }
                
else   if  (lt  ==  LetterType.Function)   // 如果是一个函数,则完整取取出函数,当作一个操作数处理
                {
                    GetCompleteFunction(expr, i,  out  tmpstr,  out  pos);
                    post.Push(tmpstr);
                    i  =  pos; //  +1;
                }

            }
            
while  (stack.Count  >   0 )
            {
                post.Push(stack.Pop());
            }

            
return  post;
        }


        
private  LetterType JudgeLetterType( char  c,  string  expr,  int  pos)
        {
            
string  op  =   " */^ " ;
            
if  ((c  <=   ' 9 '   &&  c  >=   ' 0 ' ||  (c  ==   ' . ' ))   // 操作数
            {
                
return  LetterType.Number;
            }
            
else   if  (c  ==   ' ( ' )
            {
                
return  LetterType.OpeningParenthesis;
            }
            
else   if  (c  ==   ' ) ' )
            {
                
return  LetterType.ClosingParenthesis;
            }
            
else   if  (op.IndexOf(c)  >=   0 )
            {
                
return  LetterType.SimpleOperator;
            }
            
else   if  ((c  ==   ' - ' ||  (c  ==   ' + ' )) // 要判断是减号还是负数
            {
                
if  (pos  ==   0 )
                    
return  LetterType.Number;
                
else
                {
                    
char  tmpc  =  expr[pos  -   1 ];
                    
if  (tmpc  <=   ' 9 '   &&  tmpc  >=   ' 0 ' )   // 如果前面一位是操作数
                         return  LetterType.SimpleOperator;
                    
else   if  (tmpc  ==   ' ) ' )
                        
return  LetterType.SimpleOperator;
                    
else
                        
return  LetterType.Number;
                }
            }
            
else
                
return  LetterType.Function;
        }

        
private  LetterType JudgeLetterType( char  c)
        {
            
string  op  =   " +-*/^ " ;
            
if  ((c  <=   ' 9 '   &&  c  >=   ' 0 ' ||  (c  ==   ' . ' ))   // 操作数
            {
                
return  LetterType.Number;
            }
            
else   if  (c  ==   ' ( ' )
            {
                
return  LetterType.OpeningParenthesis;
            }
            
else   if  (c  ==   ' ) ' )
            {
                
return  LetterType.ClosingParenthesis;
            }
            
else   if  (op.IndexOf(c)  >=   0 )
            {
                
return  LetterType.SimpleOperator;
            }
            
else
                
return  LetterType.Function;
        }

        
private  LetterType JudgeLetterType( string  s)
        {
            
char  c  =  s[ 0 ];
            
if  ((c  ==   ' - ' ||  (c  ==   ' + ' ))
            {
                
if  (s.Length  >   1 )
                    
return  LetterType.Number;
                
else
                    
return  LetterType.SimpleOperator;
            }

            
string  op  =   " +-*/^ " ;
            
if  ((c  <=   ' 9 '   &&  c  >=   ' 0 ' ||  (c  ==   ' . ' ))   // 操作数
            {
                
return  LetterType.Number;
            }
            
else   if  (c  ==   ' ( ' )
            {
                
return  LetterType.OpeningParenthesis;
            }
            
else   if  (c  ==   ' ) ' )
            {
                
return  LetterType.ClosingParenthesis;
            }
            
else   if  (op.IndexOf(c)  >=   0 )
            {
                
return  LetterType.SimpleOperator;
            }
            
else
                
return  LetterType.Function;
        }

        
///   <summary>
        
///  计算操作符的优先级
        
///   </summary>
        
///   <param name="c"></param>
        
///   <returns></returns>
         private   int  GetPriority( char  c)
        {
            
if  (c  ==   ' + '   ||  c  ==   ' - ' )
                
return   0 ;
            
else   if  (c  ==   ' * ' )
                
return   1 ;
            
else   if  (c  ==   ' / ' )   // 除号优先级要设得比乘号高,否则分母可能会被先运算掉
                 return   2 ;
            
else
                
return   2 ;
        }

        
///   <summary>
        
///  获取完整的函数表达式
        
///   </summary>
        
///   <param name="expr"></param>
        
///   <param name="startPos"></param>
        
///   <param name="funcStr"></param>
        
///   <param name="endPos"></param>
         private   void  GetCompleteFunction( string  expr,  int  startPos,  out   string  funcStr,  out   int  endPos)
        {
            
int  cpnum  =   0 ;
            
for  ( int  i  =  startPos; i  <=  expr.Length  -   1 ; i ++ )
            {
                
char  c  =  expr[i];
                LetterType lt  =  JudgeLetterType(c);
                
if  (lt  ==  LetterType.OpeningParenthesis)
                    cpnum ++ ;
                
else   if  (lt  ==  LetterType.ClosingParenthesis)
                {
                    cpnum -- ; // 考虑到函数嵌套的情况,消除掉内部括号
                     if  (cpnum  ==   0 )
                    {
                        endPos  =  i;
                        funcStr  =  expr.Substring(startPos, endPos  -  startPos  +   1 );
                        
return ;
                    }


                }

            }
            funcStr  =   "" ;
            endPos  =   - 1 ;
        }

        
///   <summary>
        
///  获取到完整的数字
        
///   </summary>
        
///   <param name="expr"></param>
        
///   <param name="startPos"></param>
        
///   <param name="numberStr"></param>
        
///   <param name="endPos"></param>
         private   void  GetCompleteNumber( string  expr,  int  startPos,  out   string  numberStr,  out   int  endPos)
        {
            
char  c  =  expr[startPos];
            
for  ( int  i  =  startPos  +   1 ; i  <=  expr.Length  -   1 ; i ++ )
            {
                
char  tmpc  =  expr[i];
                
if  (JudgeLetterType(tmpc)  !=  LetterType.Number)
                {
                    endPos  =  i  -   1 ;
                    numberStr  =  expr.Substring(startPos, endPos  -  startPos  +   1 );
                    
return ;
                }
            }
            numberStr  =  expr.Substring(startPos);
            endPos  =  expr.Length  -   1 ;
        }        
    }


    
///   <summary>
    
///  可以检测到的表达式错误的Exception
    
///   </summary>
     public   class  ExpressionException : Exception
    {
        
public   override   string  Message
        {
            
get
            {
                
return   base .Message;
            }
        }
    }

    
///   <summary>
    
///  字符类别
    
///   </summary>
     public   enum  LetterType
    {
        Number,
        SimpleOperator,
        Function,
        OpeningParenthesis,
        ClosingParenthesis
    }

  调用代码如下:

  string expr = txtExpression.Text;

  NEval neval = new NEval();
       return neval.Eval(expr); 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值