1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
<?php //解释器模式,把一段有规律的经常用到的内容解释成预期的内容,常用的MVC模式中的模板替换就使用了解释器模式 //一个简单的计算+-*/的计算器,代码比较臃肿。 class Calculator { public function interpreter($str) { $str = str_replace(' ', '', $str); $str = str_replace(array('+','-','*','/'), array(' + ',' - ',' * ',' / '), $str); $arr = explode(' ', $str); unset($str); $count = count($arr)-1; $offset = 1000; for($i = 0; $i < $count; ++$i) { if ($arr[$i] == '*' || $arr[$i] == '/') { $arr[$i-$offset] = $arr[$i]; if (!isset($arr[$i-1])) { $arr[$i-1] = $tmp; } $arr[$i-1-$offset] = $arr[$i-1]; $arr[$i+1-$offset] = $arr[$i+1]; unset($arr[$i-1]); unset($arr[$i]); $tmp = $arr[$i+1]; unset($arr[$i+1]); ++$i; } } $left = array(); $right = array(); ksort($arr); array_walk($arr, function($v, $k) use(&$left, &$right){ if ($k < 0) { $left[]= $v; } else { $right[]= $v; } }); unset($arr); $countLeft = count($left) - 1; $countRight = count($right) - 1; $tmp = array(); for ($i=0; $i < $countLeft; ++$i) { if ($left[$i] == '*' || $left[$i] == '/') { if (!isset($left[$i-1])) { $tmpNum = $tmp[count($tmp)-1] = $this->compute($tmpNum, $left[$i+1], $left[$i]); unset($left[$i+1]); } else { $tmpNum = $this->compute($left[$i-1], $left[$i+1], $left[$i]); $tmp[] = $tmpNum; unset($left[$i+1]); } ++$i; } } unset($left); for ($i=0; $i < $countRight; ++$i) { if ($right[$i] == '+' || $right[$i] == '-') { if ($i == 0) { $input = array(array_shift($tmp)); array_splice($right, $i, 0, $input); ++$countRight; continue; } if ($right[$i+1] == '+' || $right[$i+1] == '-') { $input = array(array_shift($tmp)); array_splice($right, $i+1, 0, $input); ++$countRight; } } } if (!empty($tmp)) { array_push($right, current($tmp)); } $rs = array_shift($right); $countRight = count($right); for ($i=0; $i < $countRight; ++$i) { if ($right[$i] == '+' || $right[$i] == '-') { $rs = $this->compute($rs, $right[$i+1], $right[$i]); } } return $rs; } private function compute($num1, $num2, $expression) { switch ($expression) { case '+': return $num1 + $num2; case '-': return $num1 - $num2; case '*': return $num1 * $num2; case '/': if ($num2 == 0) { exit('can not divide 0'); } return round($num1 / $num2, 4); default:exit('param error'); } } } $str = '1-1-2*3*2*3+1+1+2*2*2*2/3-2+3*7*2/2-1+9/3'; $calculator = new Calculator(); $rs = $calculator->interpreter($str); echo $rs; |