中缀表达式到逆波兰表达式的转换及求值

    最近要写一个工资管理软件,不可避免的要用到公式的定义及求值等问题。对于数学表达式的计算,虽然也有直接对表达式进行扫描并按照优先级逐步计算的方法,但感觉还是不如将中缀表达式转换为逆波兰表达式更容易处理。
    使用逆波兰表达式,则有以下几件工作需要去做:
    1.对中缀表达式进行语法分析,或称合法性检查。
    2.将中缀表达式转换为逆波兰表达式。
    3.计算逆波兰表达得到我们想要的值。
以下是我为实现该功能而写的一个简单的类:
None.gif using  System;
None.gif
using  System.Text;
None.gif
using  System.Collections;
None.gif
using  System.Text.RegularExpressions;
None.gif
None.gif
namespace  Seaking
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public class RpnExpression
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
检查中缀表达式的合法性#region 检查中缀表达式的合法性
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 检查中缀表达式是否合法。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="exp"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public static bool IsRight(string exp)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string pMatch=@"\([^\(^\)]+\)";//匹配最“内”层括号及表达式
InBlock.gif
            string numberMatch=@"\d+(\.\d+)?";//匹配数字
InBlock.gif
            string exMatch=@"^0([-+*/]0)*$";//匹配无括号的、用0替换所有的数字后的表达式
InBlock.gif
            
InBlock.gif            exp
=Regex.Replace(exp,numberMatch,"0");//为简化检测,用0替换所有的数字
InBlock.gif            while(Regex.IsMatch(exp,pMatch))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
foreach(Match match in Regex.Matches(exp,pMatch))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
string tmp=match.Value;
InBlock.gif                    tmp
=tmp.Substring(1,tmp.Length-2);//去掉 "("和 ")"
InBlock.gif
                    if(!Regex.IsMatch(tmp,exMatch)) return false;
ExpandedSubBlockEnd.gif                }

InBlock.gif                exp
=Regex.Replace(exp,pMatch,"0");//将最内层的括号及括号内表达式直接用一个0代替
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return Regex.IsMatch(exp,exMatch);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
生成逆波兰表达式#region 生成逆波兰表达式
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取逆波兰表达式。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="exp"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public static string RpnExp(string exp)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if(!IsRight(exp)) throw new ApplicationException("非法的中缀表达式。");
InBlock.gif            Stack skOp
=new Stack();//定义操作符堆栈
InBlock.gif
            StringBuilder rpn=new StringBuilder();//逆波兰表达式
InBlock.gif
            char[] charExp=exp.ToCharArray();//将中缀表达式转换为char数组
InBlock.gif
            string digit=string.Empty;//数字字符串
InBlock.gif

InBlock.gif            
for(int i=0;i<charExp.Length;i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
char chr=charExp[i];
InBlock.gif
InBlock.gif                
if(char.IsDigit(chr) || chr=='.')//如果是数字或小数点,添加到数字字符串中
ExpandedSubBlockStart.gifContractedSubBlock.gif
                dot.gif{
InBlock.gif                    digit
+=chr;
ExpandedSubBlockEnd.gif                }
                
InBlock.gif                
else if("+-*/".IndexOf(chr)>=0)//如果是运算符
ExpandedSubBlockStart.gifContractedSubBlock.gif
                dot.gif{
InBlock.gif                    
if(digit.Length>0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        rpn.Append(
"<" + digit + ">");//首先将数字添加到逆波兰表达式
InBlock.gif
                        digit=string.Empty;
ExpandedSubBlockEnd.gif                    }

InBlock.gif
InBlock.gif                    
//弹出操作符并添加到逆波兰表达式,直至遇到左括号或优先级较低的操作符
InBlock.gif
                    while(skOp.Count>0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        
char opInStack=(char)skOp.Pop();
InBlock.gif                        
if(opInStack=='(' || Power(opInStack)<Power(chr))
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
dot.gif{
InBlock.gif                            skOp.Push(opInStack);
InBlock.gif                            
break;
ExpandedSubBlockEnd.gif                        }

InBlock.gif                        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
dot.gif{
InBlock.gif                            rpn.Append(opInStack);
ExpandedSubBlockEnd.gif                        }

ExpandedSubBlockEnd.gif                    }

InBlock.gif
InBlock.gif                    skOp.Push(chr);
//将当前操作符压入堆栈中
ExpandedSubBlockEnd.gif
                }

InBlock.gif                
else if(chr=='(')//遇到左括号,直接压入堆栈中
ExpandedSubBlockStart.gifContractedSubBlock.gif
                dot.gif{
InBlock.gif                    skOp.Push(chr);
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if(chr==')')//遇到右括号
ExpandedSubBlockStart.gifContractedSubBlock.gif
                dot.gif{
InBlock.gif                    
if(digit.Length>0)//先将数字添加到逆波兰表达式
ExpandedSubBlockStart.gifContractedSubBlock.gif
                    dot.gif{
InBlock.gif                        rpn.Append(
"<" + digit + ">");
InBlock.gif                        digit
=string.Empty;
ExpandedSubBlockEnd.gif                    }

InBlock.gif
InBlock.gif                    
while(skOp.Count>0)//弹出运算符并添加到逆波兰表达式,直至遇到左括号
ExpandedSubBlockStart.gifContractedSubBlock.gif
                    dot.gif{
InBlock.gif                        
char opInStack=(char)skOp.Pop();
InBlock.gif                        
if(opInStack=='(')
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
dot.gif{
InBlock.gif                            
break;
ExpandedSubBlockEnd.gif                        }

InBlock.gif                        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
dot.gif{
InBlock.gif                            rpn.Append(opInStack);
ExpandedSubBlockEnd.gif                        }

ExpandedSubBlockEnd.gif                    }
            
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
//到达字符串末尾后,首先将数字添加到逆波兰表达式
InBlock.gif
            if(digit.Length>0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                rpn.Append(
"<" + digit + ">");
ExpandedSubBlockEnd.gif            }

InBlock.gif            
//弹出所有操作符并添加到逆波兰表达式
InBlock.gif
            while(skOp.Count>0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
char opInStack=(char)skOp.Pop();
InBlock.gif                rpn.Append(opInStack);
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return rpn.ToString();
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取操作符的优先级。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="o"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        private static int Power(char o)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
switch(o)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
case '+':
InBlock.gif                
case '-':
InBlock.gif                    
return 1;
InBlock.gif                
case '*':
InBlock.gif                
case '/':
InBlock.gif                    
return 2;
InBlock.gif                
default:
InBlock.gif                    
return 0;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
计算逆波兰表达式的值#region 计算逆波兰表达式的值
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取中缀表达式的值。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="exp"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public static double GetValue(string exp)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return GetValueByRpn(RpnExp(exp));
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取逆波兰表达式的值。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="rpnExp"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public static double GetValueByRpn(string rpnExp)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Stack stack
=new Stack();
InBlock.gif            
InBlock.gif            
char[] expChar=rpnExp.ToCharArray();
InBlock.gif            
string digit=string.Empty;
InBlock.gif            
double result=0;
InBlock.gif            
for(int i=0;i<expChar.Length;i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{            
InBlock.gif                
char c=expChar[i];
InBlock.gif                
if(c=='<')
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    digit
=string.Empty;
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if(c=='>')
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    stack.Push(digit);
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if(char.IsDigit(c) || c=='.')
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    digit
+=c.ToString();
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if(c=='+' || c=='-' || c=='*' || c=='/')
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
double d2=Convert.ToDouble(stack.Pop());
InBlock.gif                    
double d1=Convert.ToDouble(stack.Pop());
InBlock.gif                    result
=math(d1,d2,c);
InBlock.gif                    stack.Push(result);
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
return result;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 四则运算。
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="d1"></param>
InBlock.gif        
/// <param name="d2"></param>
InBlock.gif        
/// <param name="o"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        private static double math(double d1,double d2,char o)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
switch(o)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
case '+':
InBlock.gif                    
return d1+d2;
InBlock.gif                
case '-':
InBlock.gif                    
return d1-d2;
InBlock.gif                
case '*':
InBlock.gif                    
return d1*d2;
InBlock.gif                
case '/':
InBlock.gif                    
return d1/d2;
InBlock.gif                
default:
InBlock.gif                    
return 0d;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

    由于只是工资计算,该类只支持+-×/ 四种运算,而且不支持负数(太麻烦,呵呵),有兴趣的朋友可以自己扩充一下。

转载于:https://www.cnblogs.com/chinadhf/archive/2006/07/16/452137.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值