C#利用栈实现字符串运算解析

附上参考文章链接:https://blog.csdn.net/qq_34831781/article/details/80104219

本人整合修复一些bug后的代码

  1 using System;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.Text;
  5 
  6 // 解析计算字符串公式
  7 namespace CalcuStrFormula
  8 {
  9     // 处理类
 10     class Handler
 11     {
 12         private Stack _complexNumberStack = new Stack();
 13         private Stack _operatorStack = new Stack();
 14         private Parser _parser = new Parser();
 15         private Operators _operators = new Operators();
 16 
 17         private static Handler _instance;
 18         public static Handler instance
 19         {
 20             get
 21             {
 22                 if (_instance == null)
 23                 {
 24                     _instance = new Handler();
 25                 }
 26                 return _instance;
 27             }
 28         }
 29 
 30         public ComplexNumber Process(string inputString)
 31         {
 32             _complexNumberStack.Clear();
 33             _operatorStack.Clear();
 34 
 35             Queue<object> queue = _parser.Parse(inputString);
 36             ComplexNumber complexNumber = null;
 37             char op, topOp;
 38             int count = queue.Count;
 39             for (int i = 0; i < count; i++)
 40             {
 41                 object obj = queue.Dequeue();
 42                 if (obj is char)
 43                 {
 44                     op = (char)obj;
 45                     if (_operatorStack.Count == 0)
 46                     {
 47                         _operatorStack.Push(op);
 48                     }
 49                     else
 50                     {
 51                         topOp = (char)_operatorStack.Peek();
 52                         if (op == '(')
 53                         {
 54                             _operatorStack.Push(op);  // 左括号直接压入。不判断栈顶
 55                         }
 56                         else if (op == ')')
 57                         {
 58                             // 右括号压入前观察栈顶,若栈顶是左括号,则弹出栈顶的左括号
 59                             // 否则弹出栈顶运算符,从数栈中弹出操作数进行运算,并将结果重新压入数栈,直到遇到左括号
 60                             while ((topOp = (char)_operatorStack.Pop()) != '(')
 61                             {
 62                                 ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
 63                                 ComplexNumber c2 = null; // 符号左边数
 64                                 if (_operators.IsTwoNumOperator(topOp))
 65                                 {
 66                                     c2 = (ComplexNumber)_complexNumberStack.Pop();
 67                                 }
 68                                 ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
 69                                 _complexNumberStack.Push(c3);
 70                             }
 71                         }
 72                         else if (_operators.ComparePriority(topOp, op) <= 0)
 73                         {
 74                             // 若即将压入的运算符不是括号,则比较栈顶运算符和即将压入的运算符的优先级
 75                             // 如果栈顶优先级高,则将栈顶运算符取出运算,直到栈顶优先级不大于其。
 76                             while (_operatorStack.Count != 0 && _operators.ComparePriority((char)_operatorStack.Peek(), op) <= 0)
 77                             {
 78                                 topOp = (char)_operatorStack.Pop();
 79                                 ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
 80                                 ComplexNumber c2 = null; // 符号左边数
 81                                 if (_operators.IsTwoNumOperator(topOp))
 82                                 {
 83                                     c2 = (ComplexNumber)_complexNumberStack.Pop();
 84                                 }
 85                                 ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
 86                                 _complexNumberStack.Push(c3);
 87                             }
 88                             _operatorStack.Push(op);
 89                         }
 90                         else
 91                         {
 92                             _operatorStack.Push(op);
 93                         }
 94                     }
 95                 }
 96                 else if (obj is ComplexNumber)
 97                 {
 98                     complexNumber = (ComplexNumber)obj;
 99                     _complexNumberStack.Push(complexNumber);
100                 }
101 
102                 if (queue.Count == 0)
103                 {
104                     while (_operatorStack.Count != 0)
105                     {
106                         topOp = (char)_operatorStack.Pop();
107                         ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
108                         ComplexNumber c2 = null; // 符号左边数
109                         if (_operators.IsTwoNumOperator(topOp))
110                         {
111                             c2 = (ComplexNumber)_complexNumberStack.Pop();
112                         }
113                         ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
114                         _complexNumberStack.Push(c3);
115                     }
116                 }
117             }
118 
119             return (ComplexNumber)_complexNumberStack.Pop();
120         }
121     }
122 
123     // 3+4i解析成Queue包含 3, +, 4i
124     public class Parser
125     {
126         private Operators _operators = new Operators();
127 
128         public Queue<object> Parse(string input)
129         {
130             input = input.Replace(" ", "");
131             if (input.StartsWith("-")) input = '0' + input;
132 
133             char[] arr = input.ToCharArray();
134             Queue<char> queueChar = new Queue<char>();
135             foreach (char x in arr)
136             {
137                 queueChar.Enqueue(x);
138             }
139             Queue<object> queueResult = ParseStringQueue(queueChar);
140             return queueResult;
141         }
142 
143         // 传入字符串队列,返回封装好的队列。
144         // ComplexNumber对象或char类型运算符各占用一个结点
145         private Queue<object> ParseStringQueue(Queue<char> queue)
146         {
147             Queue<object> secondQ = new Queue<object>();
148             char c;
149             StringBuilder sb = null;
150             string temp;
151             int count = queue.Count;
152             bool flag = false; // false表示允许创建新SB对象进行缓存数字字符串
153             for (int i = 0; i < count; i++)
154             {
155                 c = queue.Dequeue();
156                 if (!_operators.Contains(c))
157                 {
158                     // 如果扫描到的不是运算符,则将其加入到buffer尾部
159                     if (!flag)
160                     {
161                         flag = true;
162                         sb = new StringBuilder();
163                     }
164                     sb.Append(c);
165                 }
166                 if (_operators.Contains(c) || queue.Count == 0)
167                 {
168                     // 如果扫描到的是运算符,则将缓冲区中的串加入队尾
169                     if (sb != null && flag == true)
170                     {
171                         temp = sb.ToString();
172                         try
173                         {
174                             if (temp.EndsWith("i"))
175                             {
176                                 if (temp.Length == 1)
177                                 {
178                                     secondQ.Enqueue(new ComplexNumber(0, 1));
179                                 }
180                                 else
181                                 {
182                                     // i前有数字则开出数字部分。
183                                     temp = temp.Substring(0, temp.Length - 1);
184                                     secondQ.Enqueue(new ComplexNumber(0, double.Parse(temp)));
185                                 }
186                             }
187                             else
188                             {
189                                 secondQ.Enqueue(new ComplexNumber(double.Parse(temp), 0));
190                             }
191                             sb = null;
192                             flag = false;
193                         }
194                         catch (Exception e)
195                         {
196                             UnityEngine.Debug.Log("Error " + e.ToString());
197                         }
198                     }
199                     // 如果是运算符,则最后将运算符放入队。
200                     if (_operators.Contains(c))
201                     {
202                         secondQ.Enqueue(c);
203                     }
204                 }
205             }
206 
207             return secondQ;
208         }
209     }
210 
211     // 复数类,提供实数域虚数域,getset方法,加减乘除以及toString()方法
212     class ComplexNumber
213     {
214         private double _realPart; // 实数部分
215         private double _imaginPart; // 虚数部分
216 
217         public ComplexNumber()
218         {
219             _realPart = 0.0;
220             _imaginPart = 0.0;
221         }
222         public ComplexNumber(double r, double i)
223         {
224             _realPart = r;
225             _imaginPart = i;
226         }
227         public ComplexNumber(ComplexNumber c)
228         {
229             _realPart = c.GetRealPart();
230             _imaginPart = c.GetImaginaryPart();
231         }
232 
233         // get,set方法
234         public double GetRealPart()
235         {
236             return _realPart;
237         }
238         public double GetImaginaryPart()
239         {
240             return _imaginPart;
241         }
242         public void SetRealPart(double d)
243         {
244             _realPart = d;
245         }
246         public void SetImaginaryPart(double d)
247         {
248             _imaginPart = d;
249         }
250 
251         //
252         public ComplexNumber ComplexAdd(ComplexNumber c)
253         {
254             return new ComplexNumber(_realPart + c.GetRealPart(), _imaginPart + c.GetImaginaryPart());
255         }
256         public ComplexNumber ComplexAdd(double c)
257         {
258             return new ComplexNumber(_realPart + c, _imaginPart);
259         }
260         //
261         public ComplexNumber ComplexMinus(ComplexNumber c)
262         {
263             return new ComplexNumber(_realPart - c.GetRealPart(), _imaginPart - c.GetImaginaryPart());
264         }
265         public ComplexNumber ComplexMinus(double c)
266         {
267             return new ComplexNumber(_realPart - c, _imaginPart);
268         }
269         //
270         public ComplexNumber ComplexMulti(ComplexNumber c)
271         {
272             return new ComplexNumber(
273             _realPart * c.GetRealPart()
274             - _imaginPart * c.GetImaginaryPart(),
275             _realPart *
276             c.GetImaginaryPart()
277             + _imaginPart *
278             c.GetRealPart());
279         }
280         public ComplexNumber ComplexMulti(double c)
281         {
282             return new ComplexNumber(_realPart * c, _imaginPart * c);
283         }
284         //
285         public ComplexNumber ComplexDivision(ComplexNumber c)
286         {
287             return new ComplexNumber((_realPart * c.GetRealPart() + _imaginPart * c.GetImaginaryPart())
288                 / (c.GetRealPart() * c.GetRealPart() + c.GetImaginaryPart() * c.GetImaginaryPart())
289                 , (_imaginPart * c.GetRealPart() - _realPart * c.GetImaginaryPart())
290                 / (c.GetRealPart() * c.GetRealPart() + c.GetImaginaryPart() * c.GetImaginaryPart()));
291         }
292         public ComplexNumber ComplexDivision(double c)
293         {
294             return new ComplexNumber(_realPart / c, _imaginPart / c);
295         }
296         //
297         public ComplexNumber ComplexPow(ComplexNumber c)
298         {
299             int pow;
300             if (int.TryParse(c.GetRealPart().ToString(), out pow))
301             {
302                 ComplexNumber origin = new ComplexNumber(this);
303                 ComplexNumber multi = new ComplexNumber(this);
304                 for (int i = 0; i < pow - 1; i++)
305                 {
306                     origin = origin.ComplexMulti(multi);
307                 }
308                 return origin;
309             }
310             else
311             {
312                 return ComplexPow(c.GetRealPart());
313             }
314         }
315         public ComplexNumber ComplexPow(double c)
316         {
317             return new ComplexNumber(Math.Pow(_realPart, c), 0.0);
318         }
319         // 最小值
320         public ComplexNumber ComplexMinimum(ComplexNumber c)
321         {
322             if (_realPart <= c.GetRealPart()) return this;
323             return c;
324         }
325         // 最大值
326         public ComplexNumber ComplexMaximum(ComplexNumber c)
327         {
328             if (_realPart >= c.GetRealPart()) return this;
329             return c;
330         }
331         // 转int
332         public ComplexNumber ToFloorInt()
333         {
334             _realPart = Math.Floor(_realPart);
335             return this;
336         }
337 
338         public override string ToString()
339         {
340             return "(" + _realPart + " + " + _imaginPart + " i" + ")";
341         }
342     }
343 
344     // 操作符类
345     class Operators
346     {
347         private char[][] _signOperator;
348 
349         public Operators()
350         {
351             // 从上到下,优先级由高到低
352             _signOperator = new char[4][];
353             _signOperator[0] = new char[4];
354             _signOperator[0][0] = '^';
355             _signOperator[0][1] = 's'; // 最小值
356             _signOperator[0][2] = 'b'; // 最大值
357             _signOperator[0][3] = 'i'; // int值
358             _signOperator[1] = new char[2];
359             _signOperator[1][0] = '*';
360             _signOperator[1][1] = '/';
361             _signOperator[2] = new char[2];
362             _signOperator[2][0] = '+';
363             _signOperator[2][1] = '-';
364             _signOperator[3] = new char[2];
365             _signOperator[3][0] = '(';
366             _signOperator[3][1] = ')';
367         }
368 
369         // 比较操作符优先级
370         public int ComparePriority(char firstSign, char secondSign)
371         {
372             int priorityF = 0, priorityS = 0;
373             for (int i = 0; i < _signOperator.Length; i++)
374             {
375                 foreach (char x in _signOperator[i])
376                 {
377                     if (firstSign == x)
378                     {
379                         priorityF = i;
380                     }
381                     if (secondSign == x)
382                     {
383                         priorityS = i;
384                     }
385                 }
386             }
387 
388             return (priorityF - priorityS);
389         }
390 
391         // 是否是需要两个参数的操作符
392         public bool IsTwoNumOperator(char op)
393         {
394             if (op == 'i') return false;
395             return true;
396         }
397 
398         public bool Contains(char x)
399         {
400             if (x == '' || x == '')
401             {
402                 UnityEngine.Debug.LogError(x + "为中文字符,请改为英文字符");
403             }
404 
405             foreach (char[] arr in _signOperator)
406             {
407                 foreach (char y in arr)
408                 {
409                     if (x == y)
410                     {
411                         return true;
412                     }
413                 }
414             }
415             return false;
416         }
417 
418         public ComplexNumber Compute(char op, ComplexNumber c1, ComplexNumber c2)
419         {
420             ComplexNumber result = null;
421             switch (op)
422             {
423                 case '+': result = c1.ComplexAdd(c2); break;
424                 case '-': result = c1.ComplexMinus(c2); break;
425                 case '*': result = c1.ComplexMulti(c2); break;
426                 case '/': result = c1.ComplexDivision(c2); break;
427                 case '^': result = c1.ComplexPow(c2); break;
428                 case 's': result = c1.ComplexMinimum(c2); break;
429                 case 'b': result = c1.ComplexMaximum(c2); break;
430                 case 'i': result = c2.ToFloorInt(); break;
431             }
432             return result;
433         }
434     }
435 }
View Code

仓促上传待整理。。。

posted @ 2019-09-18 10:14  Don_Yao  阅读(526)  评论(0编辑  收藏  举报