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 }