/****************************************************************** |
* 创 建 人: SamWang |
* 创建时间: 2011-11-29 |
* 描 述: |
* 计算器类:能直接对表达式进行计算,支持变量 |
* 原 理: 将表达式按字符压入堆栈中,然后按照各操作符的级别进行处理 |
* 版 本: V1.0 |
* 环 境: VS2005 |
******************************************************************/ |
using System; |
using System.Collections.Generic; |
using System.Text; |
using System.Windows.Forms; |
using System.Collections; |
namespace LingDang.CRM.UI.Client |
{ |
public class Calculator |
{ |
private string _expression; |
private Stack s; |
private string [] values; |
/// |
/// 构造函数 |
/// |
/// 表达式 |
/// 变量值数组 |
public Calculator ( string expression, string [] varValues ) |
{ |
this ._expression = expression.ToLower(); |
s = new Stack(); |
values = varValues; |
} |
/// |
/// 构造函数 |
/// |
/// 表达式 |
public Calculator ( string expression ) |
{ |
this ._expression = expression; |
s = new Stack(); |
} |
/// |
/// 总运行 |
/// |
/// |
public double Run() |
{ |
string expression = PostFix(); |
string [] aryString = expression.Split ( '|' ); |
foreach ( string str in aryString ) |
{ |
if ( IsNumber ( str ) || IsVarible ( str[0] ) ) |
{ |
double d; |
if ( IsVarible ( str[0] ) ) |
{ |
d = Convert.ToDouble ( GetValue ( str[0] ) ); |
} |
else |
{ |
d = Convert.ToDouble ( str.ToString() ); |
} |
AddOperands ( d ); |
} |
else |
{ |
DoOperator ( str ); |
} |
} |
return ( double ) s.Pop(); |
} |
private bool IsNumber ( string str ) |
{ |
if ( str.Length > 1 ) |
{ |
return true ; |
} |
else |
{ |
return Char.IsDigit ( str[0] ); |
} |
} |
/// |
/// 判断是否为变量,变量范围为a-z |
/// |
/// |
/// |
private bool IsVarible ( char c ) |
{ |
if ( c >= 'a' && c <= 'z' ) |
{ |
return true ; |
} |
else |
{ |
return false ; |
} |
} |
private void AddOperands ( double val ) |
{ |
s.Push ( val ); |
} |
/// |
/// 得到公式左右运算数 |
/// |
/// |
/// |
/// |
private bool GetTwoOperands ( out double left, out double right ) |
{ |
try |
{ |
right = ( double ) s.Pop(); |
left = ( double ) s.Pop(); |
} |
catch ( InvalidOperationException ) |
{ |
right = 0; |
left = 0; |
return false ; |
} |
return true ; |
} |
/// |
/// 计算操作 |
/// |
/// 运算符 |
private void DoOperator ( string op ) |
{ |
double left, right; |
bool result = GetTwoOperands ( out left, out right ); |
if ( result ) |
{ |
switch ( op ) |
{ |
case "+" : |
s.Push ( left + right ); |
break ; |
case "-" : |
s.Push ( left - right ); |
break ; |
case "*" : |
s.Push ( left * right ); |
break ; |
case "/" : |
if ( right == 0.0 ) |
{ |
s.Clear(); |
//Divide by 0! |
throw new Exception ( "除数不能为零" ); |
} |
else |
s.Push ( left / right ); |
break ; |
case "^" : |
s.Push ( Math.Pow ( left, right ) ); |
break ; |
} |
} |
else |
{ |
s.Clear(); |
} |
} |
/// |
/// 解析为后缀表达式 |
/// |
/// |
public string PostFix() |
{ |
string str = this ._expression + "#" ; |
char tempc; |
char [] chars = str.ToCharArray(); |
Stack ts = new Stack(); |
ts.Push ( '#' ); |
string str1 = "" ; |
string tmpStr = "" ; |
bool isNum = false ; |
foreach ( char c in chars ) |
{ |
if ( Char.IsDigit ( c ) || IsVarible ( c ) || c == '.' ) |
{ |
tmpStr += c.ToString(); |
isNum = true ; |
} |
else |
{ |
if ( isNum ) |
{ |
str1 += tmpStr + "|" ; |
tmpStr = "" ; |
} |
isNum = false ; |
if ( c == ')' ) |
{ |
for ( tempc = Convert.ToChar ( ts.Pop() ); tempc != '(' ; tempc = Convert.ToChar ( ts.Pop() ) ) |
str1 += tempc.ToString() + "|" ; |
} |
else |
{ |
for ( tempc = Convert.ToChar ( ts.Pop() ); Isp ( tempc ) > Icp ( c ); tempc = Convert.ToChar ( ts.Pop() ) ) |
str1 += tempc.ToString() + "|" ; |
ts.Push ( tempc ); |
ts.Push ( c ); |
} |
} |
} |
return str1.Substring ( 0, str1.Length - 1 ); |
} |
/// |
/// 根据变量名得到对应的值 |
/// |
/// 变量名:A-Z |
/// |
private string GetValue ( char c ) |
{ |
string result = "0" ; |
//变量对应的数组位置 |
int index = Convert.ToInt32 ( c ) - Convert.ToInt32 ( 'a' ); |
if ( index < values.Length ) |
{ |
result = values[index].ToString(); |
} |
return result; |
} |
private int Isp ( char c ) |
{ |
int k; |
switch ( c ) |
{ |
case '#' : |
k = 0; |
break ; |
case '(' : |
k = 1; |
break ; |
case '^' : |
k = 7; |
break ; |
case '*' : |
case '/' : |
case '%' : |
k = 5; |
break ; |
case '+' : |
case '-' : |
k = 3; |
break ; |
case ')' : |
k = 8; |
break ; |
default : |
//Unknown operator! |
throw new Exception ( "无效操作符:" +c.ToString() ); |
} |
return k; |
} |
private int Icp ( char c ) |
{ |
int k; |
switch ( c ) |
{ |
case '#' : |
k = 0; |
break ; |
case '(' : |
k = 8; |
break ; |
case '^' : |
k = 6; |
break ; |
case '*' : |
case '/' : |
case '%' : |
k = 4; |
break ; |
case '+' : |
case '-' : |
k = 2; |
break ; |
case ')' : |
k = 1; |
break ; |
default : |
//Unknown operator! |
throw new Exception ( "无效操作符:" + c.ToString() ); |
} |
return k; |
} |
} |
} |