表达式计算

  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     }
原文地址:https://www.cnblogs.com/refresh/p/2512707.html