1 /// <summary>
2 /// 提供表达式计算功能
3 /// </summary>
4 public class Expressions
5 {
6 /// <summary>
7 /// 将表达式中的操作数和运算符分割出来
8 /// </summary>
9 /// <param name="expression">文本表达式</param>
10 /// <returns>操作数与运算符表</returns>
11 internal static List<IOperatorOrOperand> SplitExpression(string expression)
12 {
13 List<IOperatorOrOperand> output = new List<IOperatorOrOperand>();
14 StringBuilder operandbuf = new StringBuilder();
15 StringBuilder operatorbuf = new StringBuilder();
16
17 // 记录刚才最后输出的表达式项
18 IOperatorOrOperand lastItem = null;
19
20 // 在尾部添加一个空格,帮助分离最后一个操作数或运算符
21 expression = expression + " ";
22
23 decimal result = 0;
24 for (int i = 0; i < expression.Length; i++)
25 {
26 if (char.IsDigit(expression[i]) == true || expression[i] == '.')
27 {
28 // 如果是数字或小数点(操作数成份)
29
30 // 结束前一个运算符
31 if (operatorbuf.Length > 0)
32 {
33 // 尝试获取运算符
34 OperatorBase opr = TryGetOperator(operatorbuf.ToString(), lastItem);
35 if (opr != null)
36 {
37 output.Add(opr);
38 lastItem = opr;
39 operatorbuf.Length = 0;
40 }
41 else
42 {
43 throw new InvalidCastException(operatorbuf.ToString() + " 无法解析为合法的运算符。");
44 }
45 }
46
47 // 合并入当前操作数项
48 operandbuf.Append(expression[i]);
49 }
50 else
51 {
52 // 不是数字或小数点(运算符成份)
53
54 // 结束前一个操作数
55 if (operandbuf.Length > 0)
56 {
57 if (decimal.TryParse(operandbuf.ToString(), out result) == false)
58 {
59 throw new FormatException(operandbuf.ToString() + " 无法解析为合法的操作数。");
60 }
61
62 // 输出操作数
63 OperandInfo operand = new OperandInfo(decimal.Parse(operandbuf.ToString()));
64 output.Add(operand);
65 lastItem = operand;
66 operandbuf.Length = 0;
67 }
68
69 // 合并非空白字符到当前运算符项
70 if (char.IsWhiteSpace(expression[i]) == false)
71 {
72 operatorbuf.Append(expression[i]);
73 }
74
75 // 分析并输出运算符
76 if (operatorbuf.Length > 0)
77 {
78 // 尝试获取运算符
79 OperatorBase opr = TryGetOperator(operatorbuf.ToString(), lastItem);
80 if (opr != null)
81 {
82 output.Add(opr);
83 lastItem = opr;
84 operatorbuf.Length = 0;
85 }
86 }
87 }
88 }
89
90 return output;
91 }
92
93 /// <summary>
94 /// 将表达式转换为后缀表达式
95 /// </summary>
96 /// <param name="expression">文本表达式</param>
97 /// <returns>转换后的后缀表达式</returns>
98 internal static List<IOperatorOrOperand> ConvertInfixToPostfix(string expression)
99 {
100 // 预处理中缀表达式
101 List<IOperatorOrOperand> infix = SplitExpression(expression);
102 // 运算符栈
103 System.Collections.Generic.Stack<OperatorBase> opr = new System.Collections.Generic.Stack<OperatorBase>();
104 // 后缀表达式输出
105 List<IOperatorOrOperand> output = new List<IOperatorOrOperand>();
106
107 // 遍历
108 foreach (IOperatorOrOperand item in infix)
109 {
110 if (item.IsOperator)
111 {
112 // 是运算符
113 if (item.GetType() == typeof(OperatorCloseBracket))
114 {
115 // 闭括号
116
117 // 弹出运算符,直至遇到左括号为止
118 while (opr.Peek().GetType() != typeof(OperatorOpenBracket))
119 {
120 output.Add(opr.Pop());
121 if (opr.Count == 0)
122 {
123 // 括号不配对
124 throw new InvalidCastException("左右括号不匹配。");
125 }
126 }
127
128 // 弹出左括号
129 opr.Pop();
130 }
131 else
132 {
133 // 其它运算符
134 OperatorBase thisopr = item as OperatorBase;
135
136 // 弹出优先级高或相等的运算符
137 int thisPriority = thisopr.Priority;
138 while (opr.Count > 0)
139 {
140 OperatorBase topopr = opr.Peek();
141 if (topopr.GetType() != typeof(OperatorOpenBracket))
142 {
143 // 如果栈顶运算符不为左括号
144 if (topopr.Priority > thisopr.Priority)
145 {
146 // 如果栈顶中的运算符优先级高于当前运算符,则输出并弹出栈
147 output.Add(opr.Pop());
148 }
149 else if (topopr.Priority == thisopr.Priority)
150 {
151 // 如果栈顶中的运算符优先级与当前运算符相等
152 if (topopr.Direction == OperatingDirection.LeftToRight)
153 {
154 // 如果栈顶运算符结合性方向为从左至右,则输出并弹出栈
155 output.Add(opr.Pop());
156 }
157 else
158 {
159 // 如果是从右至左,终止弹栈
160 break;
161 }
162 }
163 else
164 {
165 // 终止弹栈
166 break;
167 }
168 }
169 else
170 {
171 // 终止弹栈
172 break;
173 }
174 }
175
176 // 将当前运算符压入栈中
177 opr.Push(thisopr);
178 }
179 }
180 else
181 {
182 // 是操作数
183 // 直接输出
184 output.Add(item);
185 }
186 }
187
188 // 遍历结束,输出栈中全部剩余
189 while (opr.Count > 0)
190 {
191 output.Add(opr.Pop());
192 }
193
194 return output;
195 }
196
197 /// <summary>
198 /// 计算表达式的值
199 /// </summary>
200 /// <param name="expression">文本表达式</param>
201 /// <returns>计算结果</returns>
202 public static decimal Calculate(string expression)
203 {
204 // 预处理后缀表达式
205 List<IOperatorOrOperand> postfix = Expressions.ConvertInfixToPostfix(expression);
206 // 操作数栈
207 System.Collections.Generic.Stack<decimal> data = new System.Collections.Generic.Stack<decimal>();
208
209 // 遍历
210 foreach (IOperatorOrOperand item in postfix)
211 {
212 if (item.IsOperator)
213 {
214 // 运算符
215 OperatorBase opr = item as OperatorBase;
216
217 // 从操作数栈中取出操作数
218 if (data.Count < opr.OperandCount)
219 {
220 throw new InvalidCastException("无效的表达式。缺少运算符或出现多余的操作数。");
221 }
222 decimal[] operands = new decimal[opr.OperandCount];
223 for (int i = opr.OperandCount - 1; i >= 0; i--)
224 {
225 operands[i] = data.Pop();
226 }
227
228 // 计算并将结果压回栈中
229 data.Push(opr.Calculate(operands));
230 }
231 else
232 {
233 // 操作数
234 // 压入操作数栈
235 data.Push(((OperandInfo)item).Value);
236 }
237 }
238
239 // 取最后结果
240 if (data.Count != 1)
241 {
242 throw new InvalidCastException("无效的表达式。缺少运算符或出现多余的操作数。");
243 }
244 return data.Pop();
245 }
246
247 #region 运算符与操作数信息
248
249 /// <summary>
250 /// 指出运算符的结合性方向
251 /// </summary>
252 private enum OperatingDirection
253 {
254 /// <summary>
255 /// 表示从左至右的结合性方向
256 /// </summary>
257 LeftToRight,
258 /// <summary>
259 /// 表示从右至左的结合性方向
260 /// </summary>
261 RightToLeft,
262 /// <summary>
263 /// 无结合性
264 /// </summary>
265 None
266 }
267
268 /// <summary>
269 /// 表示运算符或者操作数
270 /// </summary>
271 internal interface IOperatorOrOperand
272 {
273 /// <summary>
274 /// 是否为运算符
275 /// </summary>
276 bool IsOperator
277 {
278 get;
279 }
280
281 /// <summary>
282 /// 是否为操作数
283 /// </summary>
284 bool IsOperand
285 {
286 get;
287 }
288 }
289
290 /// <summary>
291 /// 表示一个操作数所包含的信息
292 /// </summary>
293 private struct OperandInfo : IOperatorOrOperand
294 {
295 public readonly decimal Value;
296
297 public OperandInfo(decimal value)
298 {
299 Value = value;
300 }
301
302 public override string ToString()
303 {
304 return "操作数:" + Value.ToString();
305 }
306
307 #region IOperatorOrOperand 成员
308
309 public bool IsOperator
310 {
311 get { return false; }
312 }
313
314 public bool IsOperand
315 {
316 get { return true; }
317 }
318
319 #endregion
320 }
321
322 /// <summary>
323 /// 表示一个运算符所包含的信息
324 /// </summary>
325 private abstract class OperatorBase : IOperatorOrOperand
326 {
327 /// <summary>
328 /// 运算符符号
329 /// </summary>
330 public abstract string OperatorSymbol { get; }
331 /// <summary>
332 /// 运算符名称
333 /// </summary>
334 public abstract string OperatorName { get; }
335 /// <summary>
336 /// 优先级
337 /// </summary>
338 public abstract int Priority { get; }
339 /// <summary>
340 /// 结合性方向
341 /// </summary>
342 public abstract OperatingDirection Direction { get; }
343 /// <summary>
344 /// 需要的操作数个数
345 /// </summary>
346 public abstract int OperandCount { get; }
347
348 /// <summary>
349 /// 计算结果
350 /// </summary>
351 /// <param name="operands">需要的操作数</param>
352 /// <returns>返回计算结果</returns>
353 public decimal Calculate(decimal[] operands)
354 {
355 if (operands == null)
356 {
357 throw new ArgumentNullException("找不到操作数。");
358 }
359
360 if (operands.Length != OperandCount)
361 {
362 throw new ArgumentException(OperatorSymbol + " 运算符需要 " + OperandCount.ToString() +
363 " 个操作数,但只找到 " + operands.Length + " 个。");
364 }
365
366 return OnCalculate(operands);
367 }
368
369 /// <summary>
370 /// 计算结果(参数已检查)
371 /// </summary>
372 /// <param name="operands">需要的操作数(已检查)</param>
373 /// <returns>返回计算结果</returns>
374 protected abstract decimal OnCalculate(decimal[] operands);
375
376 public override string ToString()
377 {
378 return "运算符:" + OperatorName + " [" + OperatorSymbol + "]";
379 }
380
381 #region IOperatorOrOperand 成员
382
383 public bool IsOperator
384 {
385 get { return true; }
386 }
387
388 public bool IsOperand
389 {
390 get { return false; }
391 }
392
393 #endregion
394 }
395
396 /// <summary>
397 /// 表示开括号运算符
398 /// </summary>
399 private class OperatorOpenBracket : OperatorBase
400 {
401 public override string OperatorSymbol { get { return "("; } }
402 public override string OperatorName { get { return "左括号"; } }
403 public override int Priority { get { return int.MaxValue; } }
404 public override OperatingDirection Direction { get { return OperatingDirection.None; } }
405 public override int OperandCount { get { return 0; } }
406
407 protected override decimal OnCalculate(decimal[] operands)
408 {
409 throw new InvalidOperationException("无法在左括号上执行运算。");
410 }
411 }
412
413 /// <summary>
414 /// 表示闭括号运算符
415 /// </summary>
416 private class OperatorCloseBracket : OperatorBase
417 {
418 public override string OperatorSymbol { get { return ")"; } }
419 public override string OperatorName { get { return "右括号"; } }
420 public override int Priority { get { return 0; } }
421 public override OperatingDirection Direction { get { return OperatingDirection.None; } }
422 public override int OperandCount { get { return 2; } }
423
424 protected override decimal OnCalculate(decimal[] operands)
425 {
426 throw new InvalidOperationException("无法在右括号上执行运算。");
427 }
428 }
429
430 /// <summary>
431 /// 表示加法运算符
432 /// </summary>
433 private class OperatorPlus : OperatorBase
434 {
435 public override string OperatorSymbol { get { return "+"; } }
436 public override string OperatorName { get { return "加号"; } }
437 public override int Priority { get { return 12; } }
438 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
439 public override int OperandCount { get { return 2; } }
440
441 protected override decimal OnCalculate(decimal[] operands)
442 {
443 return operands[0] + operands[1];
444 }
445 }
446
447 /// <summary>
448 /// 表示减法运算符
449 /// </summary>
450 private class OperatorMinus : OperatorBase
451 {
452 public override string OperatorSymbol { get { return "-"; } }
453 public override string OperatorName { get { return "减号"; } }
454 public override int Priority { get { return 12; } }
455 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
456 public override int OperandCount { get { return 2; } }
457
458 protected override decimal OnCalculate(decimal[] operands)
459 {
460 return operands[0] - operands[1];
461 }
462 }
463
464 /// <summary>
465 /// 表示乘法运算符
466 /// </summary>
467 private class OperatorMultiply : OperatorBase
468 {
469 public override string OperatorSymbol { get { return "*"; } }
470 public override string OperatorName { get { return "乘号"; } }
471 public override int Priority { get { return 13; } }
472 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
473 public override int OperandCount { get { return 2; } }
474
475 protected override decimal OnCalculate(decimal[] operands)
476 {
477 return operands[0] * operands[1];
478 }
479 }
480
481 /// <summary>
482 /// 表示除法运算符
483 /// </summary>
484 private class OperatorDivide : OperatorBase
485 {
486 public override string OperatorSymbol { get { return "/"; } }
487 public override string OperatorName { get { return "除号"; } }
488 public override int Priority { get { return 13; } }
489 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
490 public override int OperandCount { get { return 2; } }
491
492 protected override decimal OnCalculate(decimal[] operands)
493 {
494 return operands[0] / operands[1];
495 }
496 }
497
498 /// <summary>
499 /// 表示取正运算符
500 /// </summary>
501 private class OperatorPositive : OperatorBase
502 {
503 public override string OperatorSymbol { get { return "+"; } }
504 public override string OperatorName { get { return "取正号"; } }
505 public override int Priority { get { return 15; } }
506 public override OperatingDirection Direction { get { return OperatingDirection.RightToLeft; } }
507 public override int OperandCount { get { return 1; } }
508
509 protected override decimal OnCalculate(decimal[] operands)
510 {
511 return operands[0];
512 }
513 }
514
515 /// <summary>
516 /// 表示取负运算符
517 /// </summary>
518 private class OperatorNegative : OperatorBase
519 {
520 public override string OperatorSymbol { get { return "-"; } }
521 public override string OperatorName { get { return "取负号"; } }
522 public override int Priority { get { return 15; } }
523 public override OperatingDirection Direction { get { return OperatingDirection.RightToLeft; } }
524 public override int OperandCount { get { return 1; } }
525
526 protected override decimal OnCalculate(decimal[] operands)
527 {
528 return -operands[0];
529 }
530 }
531
532 /// <summary>
533 /// 表示取余运算符
534 /// </summary>
535 private class OperatorMod : OperatorBase
536 {
537 public override string OperatorSymbol { get { return "%"; } }
538 public override string OperatorName { get { return "取余"; } }
539 public override int Priority { get { return 13; } }
540 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
541 public override int OperandCount { get { return 2; } }
542
543 protected override decimal OnCalculate(decimal[] operands)
544 {
545 return operands[0] % operands[1];
546 }
547 }
548
549 /// <summary>
550 /// 表示取幂运算符
551 /// </summary>
552 private class OperatorPower : OperatorBase
553 {
554 public override string OperatorSymbol { get { return "^"; } }
555 public override string OperatorName { get { return "取幂"; } }
556 public override int Priority { get { return 14; } }
557 public override OperatingDirection Direction { get { return OperatingDirection.RightToLeft; } }
558 public override int OperandCount { get { return 2; } }
559
560 protected override decimal OnCalculate(decimal[] operands)
561 {
562 return (decimal)Math.Pow((double)operands[0], (double)operands[1]);
563 }
564 }
565
566 /// <summary>
567 /// 表示位与运算符
568 /// </summary>
569 private class OperatorBitAnd : OperatorBase
570 {
571 public override string OperatorSymbol { get { return "AND"; } }
572 public override string OperatorName { get { return "按位与"; } }
573 public override int Priority { get { return 8; } }
574 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
575 public override int OperandCount { get { return 2; } }
576
577 protected override decimal OnCalculate(decimal[] operands)
578 {
579 int op1 = (int)operands[0];
580 int op2 = (int)operands[1];
581
582 if (op1 == operands[0] && op2 == operands[1])
583 {
584 return op1 & op2;
585 }
586 else
587 {
588 throw new InvalidCastException("AND 运算符必须用于两个整数。");
589 }
590 }
591 }
592
593 /// <summary>
594 /// 表示位或运算符
595 /// </summary>
596 private class OperatorBitOr : OperatorBase
597 {
598 public override string OperatorSymbol { get { return "OR"; } }
599 public override string OperatorName { get { return "按位或"; } }
600 public override int Priority { get { return 6; } }
601 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
602 public override int OperandCount { get { return 2; } }
603
604 protected override decimal OnCalculate(decimal[] operands)
605 {
606 int op1 = (int)operands[0];
607 int op2 = (int)operands[1];
608
609 if (op1 == operands[0] && op2 == operands[1])
610 {
611 return op1 | op2;
612 }
613 else
614 {
615 throw new InvalidCastException("OR 运算符必须用于两个整数。");
616 }
617 }
618 }
619
620 /// <summary>
621 /// 表示位异或运算符
622 /// </summary>
623 private class OperatorBitXor : OperatorBase
624 {
625 public override string OperatorSymbol { get { return "XOR"; } }
626 public override string OperatorName { get { return "按位异或"; } }
627 public override int Priority { get { return 7; } }
628 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
629 public override int OperandCount { get { return 2; } }
630
631 protected override decimal OnCalculate(decimal[] operands)
632 {
633 int op1 = (int)operands[0];
634 int op2 = (int)operands[1];
635
636 if (op1 == operands[0] && op2 == operands[1])
637 {
638 return op1 ^ op2;
639 }
640 else
641 {
642 throw new InvalidCastException("XOR 运算符必须用于两个整数。");
643 }
644 }
645 }
646
647 /// <summary>
648 /// 表示按位取反运算符
649 /// </summary>
650 private class OperatorBitReverse : OperatorBase
651 {
652 public override string OperatorSymbol { get { return "~"; } }
653 public override string OperatorName { get { return "按位取反"; } }
654 public override int Priority { get { return 15; } }
655 public override OperatingDirection Direction { get { return OperatingDirection.RightToLeft; } }
656 public override int OperandCount { get { return 1; } }
657
658 protected override decimal OnCalculate(decimal[] operands)
659 {
660 int op1 = (int)operands[0];
661
662 if (op1 == operands[0])
663 {
664 return ~op1;
665 }
666 else
667 {
668 throw new InvalidCastException("~ 运算符必须用于整数。.");
669 }
670 }
671 }
672
673 /// <summary>
674 /// 表示位左移运算符
675 /// </summary>
676 private class OperatorBitShiftLeft : OperatorBase
677 {
678 public override string OperatorSymbol { get { return "<<"; } }
679 public override string OperatorName { get { return "左移"; } }
680 public override int Priority { get { return 11; } }
681 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
682 public override int OperandCount { get { return 2; } }
683
684 protected override decimal OnCalculate(decimal[] operands)
685 {
686 int op1 = (int)operands[0];
687 int op2 = (int)operands[1];
688
689 if (op1 == operands[0] && op2 == operands[1])
690 {
691 return op1 << op2;
692 }
693 else
694 {
695 throw new InvalidCastException("<< 运算符必须用于两个整数。");
696 }
697 }
698 }
699
700 /// <summary>
701 /// 表示位异或运算符
702 /// </summary>
703 private class OperatorBitShiftRight : OperatorBase
704 {
705 public override string OperatorSymbol { get { return ">>"; } }
706 public override string OperatorName { get { return "右移"; } }
707 public override int Priority { get { return 11; } }
708 public override OperatingDirection Direction { get { return OperatingDirection.LeftToRight; } }
709 public override int OperandCount { get { return 2; } }
710
711 protected override decimal OnCalculate(decimal[] operands)
712 {
713 int op1 = (int)operands[0];
714 int op2 = (int)operands[1];
715
716 if (op1 == operands[0] && op2 == operands[1])
717 {
718 return op1 >> op2;
719 }
720 else
721 {
722 throw new InvalidCastException(">> 运算符必须用于两个整数。");
723 }
724 }
725 }
726
727 /// <summary>
728 /// 尝试返回一个运算符对象
729 /// </summary>
730 /// <param name="exp">要测试的字符串</param>
731 /// <param name="leftItem"></param>
732 /// <returns>如果成功,返回一个运算符对象实例;否则返回空</returns>
733 private static OperatorBase TryGetOperator(string exp, IOperatorOrOperand leftItem)
734 {
735 // 判断左侧是否是操作数
736 bool hasLeftOperand = false;
737 if (leftItem == null)
738 {
739 // 没有左项
740 hasLeftOperand = false;
741 }
742 else if (leftItem.IsOperand)
743 {
744 // 左项是操作数
745 hasLeftOperand = true;
746 }
747 else if (leftItem.GetType() == typeof(OperatorCloseBracket))
748 {
749 // 左项是闭括号
750 hasLeftOperand = true;
751 }
752 else
753 {
754 // 其它情况
755 hasLeftOperand = false;
756 }
757
758 // 根据符号文本判断
759 string symbol = exp.ToUpper();
760 switch (symbol)
761 {
762 case "(":
763 return new OperatorOpenBracket();
764 case ")":
765 return new OperatorCloseBracket();
766 }
767
768 // 根据左操作数情况判断
769 if (hasLeftOperand == true)
770 {
771 // 有左操作数者
772 switch (exp.ToUpper())
773 {
774 case "+":
775 return new OperatorPlus();
776 case "-":
777 return new OperatorMinus();
778 case "*":
779 return new OperatorMultiply();
780 case "/":
781 return new OperatorDivide();
782 case "%":
783 return new OperatorMod();
784 case "^":
785 return new OperatorPower();
786 case "AND":
787 return new OperatorBitAnd();
788 case "OR":
789 return new OperatorBitOr();
790 case "XOR":
791 return new OperatorBitXor();
792 case "<<":
793 return new OperatorBitShiftLeft();
794 case ">>":
795 return new OperatorBitShiftRight();
796 }
797 }
798 else
799 {
800 // 没有左操作数
801 switch (exp.ToUpper())
802 {
803 case "+":
804 return new OperatorPositive();
805 case "-":
806 return new OperatorNegative();
807 case "~":
808 return new OperatorBitReverse();
809 }
810 }
811
812 // 不可判断者,返回空
813 return null;
814 }
815
816 #endregion
817 }