1 /******************************************************************
2 * 創 建 人: SamWang
3 * 建立時間: 2011-11-29
4 * 描 述:
5 * 電腦類:能直接對表達式進行計算,支援變量
6 * 原 理: 将表達式按字元壓入堆棧中,然後按照各操作符的級别進行處理
7 * 版 本: V1.0
8 * 環 境: VS2005
9 ******************************************************************/
10 using System;
11 using System.Collections.Generic;
12 using System.Text;
13 using System.Windows.Forms;
14 using System.Collections;
15
16 namespace LingDang.CRM.UI.Client
17 {
18 public class Calculator
19 {
20 private string _expression;
21 private Stack s;
22 private string[] values;
23
24 /// <summary>
25 /// 構造函數
26 /// </summary>
27 /// <param name="expression">表達式</param>
28 /// <param name="varValues">變量值數組</param>
29 public Calculator(string expression, string[] varValues)
30 {
31 this._expression = expression.ToLower();
32 s = new Stack();
33 values = varValues;
34 }
35
36 /// <summary>
37 /// 構造函數
38 /// </summary>
39 /// <param name="expression">表達式</param>
40 public Calculator(string expression)
41 {
42 this._expression = expression;
43 s = new Stack();
44 }
45
46 /// <summary>
47 /// 總運作
48 /// </summary>
49 /// <returns></returns>
50 public double Run()
51 {
52 string expression = PostFix();
53 string[] aryString = expression.Split('|');
54
55 foreach (string str in aryString)
56 {
57 if (IsNumber(str) || IsVarible(str[0]))
58 {
59 double d;
60 if (IsVarible(str[0]))
61 {
62 d = Convert.ToDouble(GetValue(str[0]));
63 }
64 else
65 {
66 d = Convert.ToDouble(str.ToString());
67 }
68 AddOperands(d);
69 }
70 else
71 {
72 DoOperator(str);
73 }
74
75 }
76 return (double)s.Pop();
77 }
78
79
80 private bool IsNumber(string str)
81 {
82 if (str.Length > 1)
83 {
84 return true;
85 }
86 else
87 {
88 return Char.IsDigit(str[0]);
89 }
90 }
91
92 /// <summary>
93 /// 判斷是否為變量,變量範圍為a-z
94 /// </summary>
95 /// <param name="c"></param>
96 /// <returns></returns>
97 private bool IsVarible(char c)
98 {
99 if (c >= 'a' && c <= 'z')
100 {
101 return true;
102 }
103 else
104 {
105 return false;
106 }
107 }
108
109
110 private void AddOperands(double val)
111 {
112 s.Push(val);
113 }
114
115 /// <summary>
116 /// 得到公式左右運算數
117 /// </summary>
118 /// <param name="left"></param>
119 /// <param name="right"></param>
120 /// <returns></returns>
121 private bool GetTwoOperands(out double left, out double right)
122 {
123 try
124 {
125 right = (double)s.Pop();
126 left = (double)s.Pop();
127 }
128 catch (InvalidOperationException)
129 {
130 right = 0;
131 left = 0;
132 return false;
133 }
134 return true;
135 }
136
137 /// <summary>
138 /// 計算操作
139 /// </summary>
140 /// <param name="op">運算符</param>
141 private void DoOperator(string op)
142 {
143 double left, right;
144 bool result = GetTwoOperands(out left, out right);
145 if (result)
146 {
147 switch (op)
148 {
149 case "+": s.Push(left + right); break;
150 case "-": s.Push(left - right); break;
151 case "*": s.Push(left * right); break;
152 case "/":
153 if (right == 0.0)
154 {
155 s.Clear();
156 //Divide by 0!
157 throw new Exception("除數不能為零");
158 }
159 else
160 s.Push(left / right);
161 break;
162 case "^":
163 s.Push(Math.Pow(left, right));
164 break;
165 }
166 }
167 else
168 {
169 s.Clear();
170 }
171 }
172
173 /// <summary>
174 /// 解析為字尾表達式
175 /// </summary>
176 /// <returns></returns>
177 public string PostFix()
178 {
179 string str = this._expression + "#";
180 char tempc;
181 char[] chars = str.ToCharArray();
182 Stack ts = new Stack();
183 ts.Push('#');
184 string str1 = "";
185 string tmpStr = "";
186 bool isNum = false;
187 foreach (char c in chars)
188 {
189 if (Char.IsDigit(c) || IsVarible(c) || c == '.')
190 {
191 tmpStr += c.ToString();
192 isNum = true;
193 }
194 else
195 {
196 if (isNum)
197 {
198 str1 += tmpStr + "|";
199 tmpStr = "";
200 }
201 isNum = false;
202 if (c == ')')
203 {
204 for (tempc = Convert.ToChar(ts.Pop()); tempc != '('; tempc = Convert.ToChar(ts.Pop()))
205 str1 += tempc.ToString() + "|";
206 }
207 else
208 {
209 for (tempc = Convert.ToChar(ts.Pop()); Isp(tempc) > Icp(c); tempc = Convert.ToChar(ts.Pop()))
210 str1 += tempc.ToString() + "|";
211 ts.Push(tempc);
212 ts.Push(c);
213 }
214 }
215 }
216 return str1.Substring(0, str1.Length - 1);
217 }
218
219 /// <summary>
220 /// 根據變量名得到對應的值
221 /// </summary>
222 /// <param name="c">變量名:A-Z</param>
223 /// <returns></returns>
224 private string GetValue(char c)
225 {
226 string result = "0";
227 //變量對應的數組位置
228 int index = Convert.ToInt32(c) - Convert.ToInt32('a');
229 if (index < values.Length)
230 {
231 result = values[index].ToString();
232 }
233 return result;
234 }
235
236 private int Isp(char c)
237 {
238 int k;
239 switch (c)
240 {
241 case '#': k = 0; break;
242 case '(': k = 1; break;
243 case '^': k = 7; break;
244 case '*':
245 case '/':
246 case '%': k = 5; break;
247 case '+':
248 case '-': k = 3; break;
249 case ')': k = 8; break;
250 default:
251 //Unknown operator!
252 throw new Exception("無效操作符:"+c.ToString());
253 }
254 return k;
255 }
256
257 private int Icp(char c)
258 {
259 int k;
260 switch (c)
261 {
262 case '#': k = 0; break;
263 case '(': k = 8; break;
264 case '^': k = 6; break;
265 case '*':
266 case '/':
267 case '%': k = 4; break;
268 case '+':
269 case '-': k = 2; break;
270 case ')': k = 1; break;
271 default:
272 //Unknown operator!
273 throw new Exception("無效操作符:" + c.ToString());
274 }
275 return k;
276 }
277 }
278 }
作者:SamWang
出處:http://wangshenhe.cnblogs.com/
本文版權歸作者和部落格園共有,歡迎圍觀轉載。轉載時請您務必在文章明顯位置給出原文連結,謝謝您的合作。
轉載于:https://www.cnblogs.com/wangshenhe/archive/2012/05/09/2492093.html