| 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; | 

