ArithmeticCount.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <?php
  2. namespace app\common\util;
  3. class ArithmeticCount
  4. {
  5. //运算符栈,在栈里插入最小优先级的运算符,避免进入不到去运算符比较的循环里
  6. protected $opArr = ['#'];
  7. //运算数栈;
  8. protected $oprandArr = [];
  9. //运算符优先级
  10. protected $opLevelArr = [
  11. ')' => 2,
  12. '(' => 3,
  13. '+' => 4,
  14. '-' => 4,
  15. '*' => 5,
  16. '/' => 5,
  17. '#' => 1
  18. ];
  19. protected $bolanExprArr = [];
  20. protected $exprLen=0;
  21. protected $inop = false;
  22. protected $opNums = "";
  23. protected $expr="";
  24. protected $bai=false;
  25. /**
  26. * Notes: 百分号转数字 查找替换
  27. * author 何腾骥
  28. * Date: 2018/9/27
  29. * Time: 11:51
  30. * @param $expr
  31. * @return array|string|string[]
  32. */
  33. protected function doReplace($expr)
  34. {
  35. $expr = str_replace(' ','' ,$expr);
  36. $expr = str_replace('(','(' ,$expr);
  37. $expr = str_replace(')',')' ,$expr);
  38. $expr = str_replace(' ','' ,$expr);
  39. preg_match_all("/\d+(\.\d+)?%/",$expr,$arr);
  40. if(isset($arr[0]) && !empty($arr[0])){
  41. foreach ($arr[0] as $val){
  42. $expr = str_replace($val,(float) $val /100 ,$expr);
  43. }
  44. return $expr;
  45. }
  46. if(preg_match("/100-\(/",$expr,$arr)){
  47. $expr = str_replace('100-','' ,$expr);
  48. $this->bai = true;
  49. }
  50. return $expr;
  51. }
  52. /**
  53. * Notes: 处理 计算
  54. * author 何腾骥
  55. * Date: 2018/9/27
  56. * Time: 11:53
  57. */
  58. public function makeCount($expr)
  59. {
  60. error_reporting(0);
  61. // 处理百分号
  62. $this->expr = $this->doReplace($expr);
  63. // 计算长度
  64. $this->exprLen = strlen($expr);
  65. //解析表达式
  66. for($i = 0;$i <= $this->exprLen;$i++){
  67. $char = $this->expr[$i];
  68. //获取当前字符的优先级
  69. $level = intval($this->opLevelArr[$char]);
  70. //如果大于0,表示是运算符,否则是运算数,直接输出
  71. if($level > 0){
  72. $this->inop = true;
  73. //如果碰到左大括号,直接入栈
  74. if($level == 3){
  75. array_push($this->opArr,$char);continue;
  76. }
  77. //与栈顶运算符比较,如果当前运算符优先级小于栈顶运算符,则栈顶运算符弹出,一直到当前运算符优先级不小于栈顶
  78. while($op = array_pop($this->opArr)){
  79. if($op){
  80. $currentLevel = intval($this->opLevelArr[$op]);
  81. if($currentLevel == 3 && $level == 2) {
  82. break;
  83. }elseif($currentLevel >= $level && $currentLevel != 3){
  84. array_push($this->bolanExprArr,$op);
  85. }else{
  86. array_push($this->opArr,$op);
  87. array_push($this->opArr,$char);
  88. break;
  89. }
  90. }
  91. }
  92. }else{
  93. //多位数拼接成一位数
  94. $this->opNums .= $char;
  95. if($this->opLevelArr[$this->expr[$i+1]] > 0){
  96. array_push($this->bolanExprArr, $this->opNums);
  97. $this->opNums = "";
  98. }
  99. }
  100. }
  101. array_push($this->bolanExprArr, $this->opNums);
  102. //输出剩余运算符
  103. while($leftOp = array_pop($this->opArr)){
  104. if($leftOp != '#'){
  105. array_push($this->bolanExprArr,$leftOp);
  106. }
  107. }
  108. //计算逆波兰表达式。
  109. foreach($this->bolanExprArr as $v){
  110. if(!isset($this->opLevelArr[$v])){
  111. array_push($this->oprandArr,$v);
  112. }else{
  113. $op1 = array_pop($this->oprandArr);
  114. $op2 = array_pop($this->oprandArr);
  115. eval("\$result = $op2 $v $op1;");
  116. array_push($this->oprandArr,$result);
  117. }
  118. }
  119. if($this->bai){
  120. return 100 - $result;
  121. }
  122. return $result;
  123. }
  124. }