///
<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棧,以#做爲數字的結束
* 二、若讀到的是(,則直接存入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
}