.net表達(dá)式計(jì)算器(中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式,支持20多個(gè)數(shù)學(xué)函數(shù),支持函數(shù)嵌套,免費(fèi)共享~)
最近在網(wǎng)上查了一下表達(dá)工計(jì)算器的類庫(kù),發(fā)現(xiàn)Java版本的有一個(gè)比較成熟的叫W3EVal,好像是一個(gè)IBM工程師寫(xiě)的,.net就很少了(可能是我了解不夠多),但投機(jī)取巧的實(shí)現(xiàn)思路有很多,比如:
(1)將Javasript中代碼編譯成.net類庫(kù),利用Javascript中的eval函數(shù)來(lái)實(shí)現(xiàn);
(2)利用ScriptControl執(zhí)行JavaScript腳本實(shí)現(xiàn);
(3)利用DataTable的計(jì)算功能實(shí)現(xiàn)簡(jiǎn)單計(jì)算;
(4)利用.net動(dòng)態(tài)編譯功能來(lái)實(shí)現(xiàn)等
這些方法在csdn的壇里有討論,請(qǐng)見(jiàn):http://topic.csdn.net/u/20070301/13/c8c33bd1-f146-4b44-9882-aab6d430f724.html
心想既然還沒(méi)有成熟的.net類庫(kù),何不自己做一個(gè)呢,其實(shí)并不難,只要稍有點(diǎn)耐心調(diào)試一下就好了。于是參考一編中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式的論文,很快寫(xiě)了一個(gè),發(fā)現(xiàn)效果不錯(cuò),所以發(fā)出來(lái)跟大家共享,希望對(duì)大家有用。
中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式的步驟為:
1.新建一個(gè)Stack棧,用來(lái)存放運(yùn)算符
2.新建一個(gè)post棧,用來(lái)存放最后的后綴表達(dá)式
3.從左到右掃描中綴表達(dá)式:
(1)若讀到的是操作數(shù),直接存入post棧,以#作為數(shù)字的結(jié)束
(2)若讀到的是(,則直接存入stack棧
(3)若讀到的是),則將stack棧中(前的所有運(yùn)算符出棧,存入post棧
(4)若讀到的是其它運(yùn)算符,則將該運(yùn)算符和stack棧頂運(yùn)算符作比較:若高于或等于棧頂運(yùn)算符,則直接存入stack棧,否則將棧頂運(yùn)算符(所有優(yōu)先級(jí)高于讀到的運(yùn)算符的,不包括括號(hào))出棧,存入post棧。最后將讀到的運(yùn)算符入棧。
4.當(dāng)掃描完后,stack棧中還在運(yùn)算符時(shí),則將所有的運(yùn)算符出棧,存入post棧
計(jì)算后綴表達(dá)式的值的步驟為:
1.初始化一個(gè)空堆棧
2.從左到右讀入后綴表達(dá)式
3.如果字符是一個(gè)操作數(shù),把它壓入堆棧。
4.如果字符是個(gè)操作符,彈出兩個(gè)操作數(shù),執(zhí)行恰當(dāng)操作,然后把結(jié)果壓入堆棧。如果您不能夠彈出兩個(gè)操作數(shù),后綴表達(dá)式的語(yǔ)法就不正確。
5.到后綴表達(dá)式末尾,從堆棧中彈出結(jié)果。若后綴表達(dá)式格式正確,那么堆棧應(yīng)該為空。
代碼
(1)將Javasript中代碼編譯成.net類庫(kù),利用Javascript中的eval函數(shù)來(lái)實(shí)現(xiàn);
(2)利用ScriptControl執(zhí)行JavaScript腳本實(shí)現(xiàn);
(3)利用DataTable的計(jì)算功能實(shí)現(xiàn)簡(jiǎn)單計(jì)算;
(4)利用.net動(dòng)態(tài)編譯功能來(lái)實(shí)現(xiàn)等
這些方法在csdn的壇里有討論,請(qǐng)見(jiàn):http://topic.csdn.net/u/20070301/13/c8c33bd1-f146-4b44-9882-aab6d430f724.html
心想既然還沒(méi)有成熟的.net類庫(kù),何不自己做一個(gè)呢,其實(shí)并不難,只要稍有點(diǎn)耐心調(diào)試一下就好了。于是參考一編中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式的論文,很快寫(xiě)了一個(gè),發(fā)現(xiàn)效果不錯(cuò),所以發(fā)出來(lái)跟大家共享,希望對(duì)大家有用。
中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式的步驟為:
1.新建一個(gè)Stack棧,用來(lái)存放運(yùn)算符
2.新建一個(gè)post棧,用來(lái)存放最后的后綴表達(dá)式
3.從左到右掃描中綴表達(dá)式:
(1)若讀到的是操作數(shù),直接存入post棧,以#作為數(shù)字的結(jié)束
(2)若讀到的是(,則直接存入stack棧
(3)若讀到的是),則將stack棧中(前的所有運(yùn)算符出棧,存入post棧
(4)若讀到的是其它運(yùn)算符,則將該運(yùn)算符和stack棧頂運(yùn)算符作比較:若高于或等于棧頂運(yùn)算符,則直接存入stack棧,否則將棧頂運(yùn)算符(所有優(yōu)先級(jí)高于讀到的運(yùn)算符的,不包括括號(hào))出棧,存入post棧。最后將讀到的運(yùn)算符入棧。
4.當(dāng)掃描完后,stack棧中還在運(yùn)算符時(shí),則將所有的運(yùn)算符出棧,存入post棧
計(jì)算后綴表達(dá)式的值的步驟為:
1.初始化一個(gè)空堆棧
2.從左到右讀入后綴表達(dá)式
3.如果字符是一個(gè)操作數(shù),把它壓入堆棧。
4.如果字符是個(gè)操作符,彈出兩個(gè)操作數(shù),執(zhí)行恰當(dāng)操作,然后把結(jié)果壓入堆棧。如果您不能夠彈出兩個(gè)操作數(shù),后綴表達(dá)式的語(yǔ)法就不正確。
5.到后綴表達(dá)式末尾,從堆棧中彈出結(jié)果。若后綴表達(dá)式格式正確,那么堆棧應(yīng)該為空。
類庫(kù)的名稱就名為NEval ,感覺(jué)還比較健壯,速度很快,支持20個(gè)數(shù)學(xué)函數(shù),很容易擴(kuò)充。目前還沒(méi)有表達(dá)式合法性檢查的功能,有興趣的朋友可以擴(kuò)充一下,先謝謝。
代碼如下:
代碼/// <summary>
/// 表達(dá)式計(jì)算類。支持?jǐn)?shù)學(xué)函數(shù),支持函數(shù)嵌套
/// 作者watsonyin
/// 開(kāi)發(fā)日期: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("表達(dá)式錯(cuò)誤");
}
}
private Random m_Random = null;
private double Calc_Internal(string expr)
{
/*
* 1. 初始化一個(gè)空堆棧
* 2. 從左到右讀入后綴表達(dá)式
* 3. 如果字符是一個(gè)操作數(shù),把它壓入堆棧。
* 4. 如果字符是個(gè)操作符,彈出兩個(gè)操作數(shù),執(zhí)行恰當(dāng)操作,然后把結(jié)果壓入堆棧。如果您不能夠彈出兩個(gè)操作數(shù),后綴表達(dá)式的語(yǔ)法就不正確。
* 5. 到后綴表達(dá)式末尾,從堆棧中彈出結(jié)果。若后綴表達(dá)式格式正確,那么堆棧應(yīng)該為空。
*/
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) //如果是函數(shù)
{
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("未定義的函數(shù):" + funcName);
}
}
}
object obj = stack.Pop();
return double.Parse(obj.ToString());
}
/// <summary>
/// 將函數(shù)括號(hào)內(nèi)的字符串進(jìn)行分割,獲得參數(shù)列表,如果參數(shù)是嵌套的函數(shù),用遞歸法計(jì)算得到它的值
/// </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;
}
}
//如果參數(shù)是函數(shù), 進(jìn)一步采用遞歸的方法生成函數(shù)值
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>
/// 將中綴表達(dá)式轉(zhuǎn)為后綴表達(dá)式
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
private Stack ConvertExprBack(string expr)
{
/*
* 新建一個(gè)Stack棧,用來(lái)存放運(yùn)算符
* 新建一個(gè)post棧,用來(lái)存放最后的后綴表達(dá)式
* 從左到右掃描中綴表達(dá)式:
* 1.若讀到的是操作數(shù),直接存入post棧,以#作為數(shù)字的結(jié)束
* 2、若讀到的是(,則直接存入stack棧
* 3.若讀到的是),則將stack棧中(前的所有運(yùn)算符出棧,存入post棧
* 4 若讀到的是其它運(yùn)算符,則將該運(yùn)算符和stack棧頂運(yùn)算符作比較:若高于或等于棧頂運(yùn)算符, 則直接存入stack棧,
* 否則將棧頂運(yùn)算符(所有優(yōu)先級(jí)高于讀到的運(yùn)算符的,不包括括號(hào))出棧,存入post棧。最后將讀到的運(yùn)算符入棧
* 當(dāng)掃描完后,stack棧中還在運(yùn)算符時(shí),則將所有的運(yùn)算符出棧,存入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) //操作數(shù)
{
GetCompleteNumber(expr, i, out tmpstr, out pos);
post.Push(tmpstr);
i = pos;// +1;
}
else if (lt == LetterType.OpeningParenthesis) //左括號(hào)(
{
stack.Push(c);
}
else if (lt == LetterType.ClosingParenthesis) //右括號(hào))
{
while (stack.Count > 0)
{
if (stack.Peek().ToString() == "(")
{
stack.Pop();
break;
}
else
post.Push(stack.Pop());
}
}
else if (lt == LetterType.SimpleOperator) //其它運(yùn)算符
{
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) //如果是一個(gè)函數(shù),則完整取取出函數(shù),當(dāng)作一個(gè)操作數(shù)處理
{
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 == '.')) //操作數(shù)
{
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 == '+'))//要判斷是減號(hào)還是負(fù)數(shù)
{
if (pos == 0)
return LetterType.Number;
else
{
char tmpc = expr[pos - 1];
if (tmpc <= '9' && tmpc >= '0') //如果前面一位是操作數(shù)
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 == '.')) //操作數(shù)
{
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 == '.')) //操作數(shù)
{
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>
/// 計(jì)算操作符的優(yōu)先級(jí)
/// </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 == '/') //除號(hào)優(yōu)先級(jí)要設(shè)得比乘號(hào)高,否則分母可能會(huì)被先運(yùn)算掉
return 2;
else
return 2;
}
/// <summary>
/// 獲取完整的函數(shù)表達(dá)式
/// </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--;//考慮到函數(shù)嵌套的情況,消除掉內(nèi)部括號(hào)
if (cpnum == 0)
{
endPos = i;
funcStr = expr.Substring(startPos, endPos - startPos + 1);
return;
}
}
}
funcStr = "";
endPos = -1;
}
/// <summary>
/// 獲取到完整的數(shù)字
/// </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>
/// 可以檢測(cè)到的表達(dá)式錯(cuò)誤的Exception
/// </summary>
public class ExpressionException : Exception
{
public override string Message
{
get
{
return base.Message;
}
}
}
/// <summary>
/// 字符類別
/// </summary>
public enum LetterType
{
Number,
SimpleOperator,
Function,
OpeningParenthesis,
ClosingParenthesis
}
/// 表達(dá)式計(jì)算類。支持?jǐn)?shù)學(xué)函數(shù),支持函數(shù)嵌套
/// 作者watsonyin
/// 開(kāi)發(fā)日期: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("表達(dá)式錯(cuò)誤");
}
}
private Random m_Random = null;
private double Calc_Internal(string expr)
{
/*
* 1. 初始化一個(gè)空堆棧
* 2. 從左到右讀入后綴表達(dá)式
* 3. 如果字符是一個(gè)操作數(shù),把它壓入堆棧。
* 4. 如果字符是個(gè)操作符,彈出兩個(gè)操作數(shù),執(zhí)行恰當(dāng)操作,然后把結(jié)果壓入堆棧。如果您不能夠彈出兩個(gè)操作數(shù),后綴表達(dá)式的語(yǔ)法就不正確。
* 5. 到后綴表達(dá)式末尾,從堆棧中彈出結(jié)果。若后綴表達(dá)式格式正確,那么堆棧應(yīng)該為空。
*/
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) //如果是函數(shù)
{
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("未定義的函數(shù):" + funcName);
}
}
}
object obj = stack.Pop();
return double.Parse(obj.ToString());
}
/// <summary>
/// 將函數(shù)括號(hào)內(nèi)的字符串進(jìn)行分割,獲得參數(shù)列表,如果參數(shù)是嵌套的函數(shù),用遞歸法計(jì)算得到它的值
/// </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;
}
}
//如果參數(shù)是函數(shù), 進(jìn)一步采用遞歸的方法生成函數(shù)值
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>
/// 將中綴表達(dá)式轉(zhuǎn)為后綴表達(dá)式
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
private Stack ConvertExprBack(string expr)
{
/*
* 新建一個(gè)Stack棧,用來(lái)存放運(yùn)算符
* 新建一個(gè)post棧,用來(lái)存放最后的后綴表達(dá)式
* 從左到右掃描中綴表達(dá)式:
* 1.若讀到的是操作數(shù),直接存入post棧,以#作為數(shù)字的結(jié)束
* 2、若讀到的是(,則直接存入stack棧
* 3.若讀到的是),則將stack棧中(前的所有運(yùn)算符出棧,存入post棧
* 4 若讀到的是其它運(yùn)算符,則將該運(yùn)算符和stack棧頂運(yùn)算符作比較:若高于或等于棧頂運(yùn)算符, 則直接存入stack棧,
* 否則將棧頂運(yùn)算符(所有優(yōu)先級(jí)高于讀到的運(yùn)算符的,不包括括號(hào))出棧,存入post棧。最后將讀到的運(yùn)算符入棧
* 當(dāng)掃描完后,stack棧中還在運(yùn)算符時(shí),則將所有的運(yùn)算符出棧,存入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) //操作數(shù)
{
GetCompleteNumber(expr, i, out tmpstr, out pos);
post.Push(tmpstr);
i = pos;// +1;
}
else if (lt == LetterType.OpeningParenthesis) //左括號(hào)(
{
stack.Push(c);
}
else if (lt == LetterType.ClosingParenthesis) //右括號(hào))
{
while (stack.Count > 0)
{
if (stack.Peek().ToString() == "(")
{
stack.Pop();
break;
}
else
post.Push(stack.Pop());
}
}
else if (lt == LetterType.SimpleOperator) //其它運(yùn)算符
{
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) //如果是一個(gè)函數(shù),則完整取取出函數(shù),當(dāng)作一個(gè)操作數(shù)處理
{
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 == '.')) //操作數(shù)
{
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 == '+'))//要判斷是減號(hào)還是負(fù)數(shù)
{
if (pos == 0)
return LetterType.Number;
else
{
char tmpc = expr[pos - 1];
if (tmpc <= '9' && tmpc >= '0') //如果前面一位是操作數(shù)
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 == '.')) //操作數(shù)
{
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 == '.')) //操作數(shù)
{
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>
/// 計(jì)算操作符的優(yōu)先級(jí)
/// </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 == '/') //除號(hào)優(yōu)先級(jí)要設(shè)得比乘號(hào)高,否則分母可能會(huì)被先運(yùn)算掉
return 2;
else
return 2;
}
/// <summary>
/// 獲取完整的函數(shù)表達(dá)式
/// </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--;//考慮到函數(shù)嵌套的情況,消除掉內(nèi)部括號(hào)
if (cpnum == 0)
{
endPos = i;
funcStr = expr.Substring(startPos, endPos - startPos + 1);
return;
}
}
}
funcStr = "";
endPos = -1;
}
/// <summary>
/// 獲取到完整的數(shù)字
/// </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>
/// 可以檢測(cè)到的表達(dá)式錯(cuò)誤的Exception
/// </summary>
public class ExpressionException : Exception
{
public override string Message
{
get
{
return base.Message;
}
}
}
/// <summary>
/// 字符類別
/// </summary>
public enum LetterType
{
Number,
SimpleOperator,
Function,
OpeningParenthesis,
ClosingParenthesis
}
調(diào)用代碼如下:
string expr = txtExpression.Text;
NEval neval = new NEval();
return neval.Eval(expr);
posted on 2010-10-13 14:24 西西吹雪 閱讀(1576) 評(píng)論(7) 收藏 舉報(bào)

浙公網(wǎng)安備 33010602011771號(hào)