有个网友写信给我谈到关于PHP计算工资问题。我以前一篇文章中谈到过一种计算工资的方法,不过是偷巧,利用现有的表达式的工具,现在既然有人想要,我就给出一个逆波兰的算法。我们的目标是实现如下的计算公式:假设有一个计算公式如下: $expression = "(F1*F12+10.34)";登录后复制其中的变量值如下:$expression_value = Array('F1'=>10,'F12'=>20);登录后复制我们希望用PHP构建一个类来计算出这个表达式的值。这种应用主要用于web工资管理中,用户可以自定义其工资相公式的情况。$rpn = new Math_Rpn();$rpn->setExpressionValue($expression_value); echo $rpn->calculate($expression,'deg',false); // 即为相应的值登录后复制解析逆波兰表达式的方法,编译原理中有,就是先把表达式分解成符号数组,然后求逆波兰式,最后根据逆波兰式得到其结果。我分别把三个函数贴在下面,其实本质我就是对Pear的RPN函数进行了Hack。function _stringToArray () {$temp_operator = null;$temp_value = null;$this->_input = str_replace(" ","",$this->_input);for($i = 0; $i _input); $i++) {if ($this->_input[$i] == ' ') { if ($temp_operator != null) {array_push($this->_input_array, $temp_operator);$temp_operator = null; } if ($temp_value != null) {array_push($this->_input_array, $temp_value);$temp_value = null; }} elseif (($temp_value == null) && $temp_operator != ')' && (!array_key_exists($temp_operator,$this->_operation) || !array_key_exists(2,$this->_operation[$temp_operator]) || $this->_operation[$temp_operator][2]>0) && ($this->_input[$i] == '-')) { if ($temp_operator != null) {array_push($this->_input_array, $temp_operator);$temp_operator = null; } array_push($this->_input_array, '-1'); array_push($this->_input_array, '*');//} elseif ((is_numeric($this->_input[$i])) || ($this->_input[$i] == '.')) {} elseif ((is_numeric($this->_input[$i])) || ($this->_input[$i] == '.') || ($this->_input[$i] == 'F')) { if ($temp_operator != null) {array_push($this->_input_array, $temp_operator);$temp_operator = null; } $temp_value .= $this->_input[$i];} else { if ($this->_keyExists($temp_operator, $this->_operation, 1)) {array_push($this->_input_array, $temp_operator);$temp_operator = null; } if ($temp_value != null) {array_push($this->_input_array, $temp_value);$temp_value = null; } $temp_operator .= $this->_input[$i];}}if ($temp_operator != null && $temp_operator != ' ') {array_push($this->_input_array, $temp_operator);} elseif($temp_value != null && $temp_value != ' ') {array_push($this->_input_array, $temp_value);}// $this->_testInput();print_r($this->_expression_value);print_r($this->_input_array);return $this->_input_array; } function _arrayToRpn() {if ($this->_error null) {$this->_output = array();return $this->_output;}for($i = 0; $i _input_array); $i++) {$temp = $this->_input_array[$i];if (is_numeric($temp)) { $this->_outputAdd($temp);} else if($this->_keyExists($temp, $this->_expression_value, 0)) { $this->_outputAdd($this->_expression_value[$temp]);} else { if ($temp == ')') {while(!$this->_stackEmpty() && ($this->_stackPriority() >= 1)) {$this->_outputAdd($this->_stackDelete());}if (!$this->_stackEmpty()) {$this->_stackDelete();} } elseif ($temp=='(') {$this->_stackAdd($temp); } elseif (($this->_stackEmpty()) || (($this->_priority($temp) > $this->_stackPriority()))) {$this-> _stackAdd($temp); } else {while(!$this->_stackEmpty() && ($this->_priority($temp) _stackPriority())) {$this->_outputAdd($this->_stackDelete());}$this->_stackAdd($temp); }}}while(!$this->_stackEmpty()) {$this->_outputAdd($this->_stackDelete());}return $this->_output;}function _rpnToValue() {$time1 = $this->_getMicroTime();if ($this->_error null) {$this->_value = null;return $this->_value;}$this->_value = 0;$temp = $this->_output;do {$pos = $this->_nextOperator($temp);if ($pos == -1) { $this->_error = $this->_raiseError('Syntax error'); $this->_value = null; return $this->_value;}$operator = $this->_operation[$temp[$pos]];$arg = $operator[2];$function = $operator[3];if (($arg==2) && (!isset($temp[$pos-1]) || !is_numeric($temp[$pos-1]) || !isset($temp[$pos-2]) || !is_numeric($temp[$pos-2]))) { $this->_error = $this->_raiseError('Syntax error'); $this->_value = null; return $this->_value;} elseif (($arg==1) && (!isset($temp[$pos-1]) || !is_numeric($temp[$pos-1]))) { $this->_error = $this->_raiseError('Syntax error'); $this->_value = null; return $this->_value;}if(is_array($function)) { if($arg==2) $arg_array = array($temp[$pos-2],$temp[$pos-1]); elseif($arg==1) $arg_array = array($temp[$pos-1]); else $arg_array = array(); if($function['type'] == 'userFunction') {$this->_value = call_user_func_array($function['function'], $arg_array); } else {$function_array = array(&$function['class'], $function['method']);$this->_value = call_user_func_array($function_array, $arg_array); }} else { $this->_value = $this->$function($temp, $pos);}if ($this->_isNan($this->_value)) { $this->_error = $this->_raiseError('NAN value'); $this->_value = null; return $this->_value;} elseif ($this->_isInfinite($this->_value)) { $this->_error = $this->_raiseError('Infinite value'); $this->_value = null; return $this->_value;} elseif (is_null($this->_value)) { return $this->_value;}$temp = $this->_refresh($temp, $pos, $arg, $this->_value);} while(count($temp) > 1);$this->_value = $temp[0];$time2 = $this->_getMicroTime();$this->_timer = $time2 - $time1;return $this->_value; }登录后复制 09-19 01:26