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 }
仓促上传待整理。。。