📄 parser.php
字号:
return $this->raiseError("Column in: $cell greater than 255"); } // FIXME: change for BIFF8 if ($row >= 16384) { return $this->raiseError("Row in: $cell greater than 16384 "); } // Set the high bits to indicate if row or col are relative. if ($this->_BIFF_version == 0x0500) { $row |= $col_rel << 14; $row |= $row_rel << 15; $col = pack('C', $col); } elseif ($this->_BIFF_version == 0x0600) { $col |= $col_rel << 14; $col |= $row_rel << 15; $col = pack('v', $col); } $row = pack('v', $row); return array($row, $col); } /** * pack() row range into the required 3 or 4 byte format. * Just using maximum col/rows, which is probably not the correct solution * * @access private * @param string $range The Excel range to be packed * @return array Array containing (row1,col1,row2,col2) in packed() format */ function _rangeToPackedRange($range) { preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match); // return absolute rows if there is a $ in the ref $row1_rel = empty($match[1]) ? 1 : 0; $row1 = $match[2]; $row2_rel = empty($match[3]) ? 1 : 0; $row2 = $match[4]; // Convert 1-index to zero-index $row1--; $row2--; // Trick poor inocent Excel $col1 = 0; $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!) // FIXME: this changes for BIFF8 if (($row1 >= 16384) or ($row2 >= 16384)) { return $this->raiseError("Row in: $range greater than 16384 "); } // Set the high bits to indicate if rows are relative. if ($this->_BIFF_version == 0x0500) { $row1 |= $row1_rel << 14; // FIXME: probably a bug $row2 |= $row2_rel << 15; $col1 = pack('C', $col1); $col2 = pack('C', $col2); } elseif ($this->_BIFF_version == 0x0600) { $col1 |= $row1_rel << 15; $col2 |= $row2_rel << 15; $col1 = pack('v', $col1); $col2 = pack('v', $col2); } $row1 = pack('v', $row1); $row2 = pack('v', $row2); return array($row1, $col1, $row2, $col2); } /** * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero * indexed row and column number. Also returns two (0,1) values to indicate * whether the row or column are relative references. * * @access private * @param string $cell The Excel cell reference in A1 format. * @return array */ function _cellToRowcol($cell) { preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match); // return absolute column if there is a $ in the ref $col_rel = empty($match[1]) ? 1 : 0; $col_ref = $match[2]; $row_rel = empty($match[3]) ? 1 : 0; $row = $match[4]; // Convert base26 column string to a number. $expn = strlen($col_ref) - 1; $col = 0; $col_ref_length = strlen($col_ref); for ($i = 0; $i < $col_ref_length; $i++) { $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn); $expn--; } // Convert 1-index to zero-index $row--; $col--; return array($row, $col, $row_rel, $col_rel); } /** * Advance to the next valid token. * * @access private */ function _advance() { $i = $this->_current_char; $formula_length = strlen($this->_formula); // eat up white spaces if ($i < $formula_length) { while ($this->_formula{$i} == " ") { $i++; } if ($i < ($formula_length - 1)) { $this->_lookahead = $this->_formula{$i+1}; } $token = ''; } while ($i < $formula_length) { $token .= $this->_formula{$i}; if ($i < ($formula_length - 1)) { $this->_lookahead = $this->_formula{$i+1}; } else { $this->_lookahead = ''; } if ($this->_match($token) != '') { //if ($i < strlen($this->_formula) - 1) { // $this->_lookahead = $this->_formula{$i+1}; //} $this->_current_char = $i + 1; $this->_current_token = $token; return 1; } if ($i < ($formula_length - 2)) { $this->_lookahead = $this->_formula{$i+2}; } else { // if we run out of characters _lookahead becomes empty $this->_lookahead = ''; } $i++; } //die("Lexical error ".$this->_current_char); } /** * Checks if it's a valid token. * * @access private * @param mixed $token The token to check. * @return mixed The checked token or false on failure */ function _match($token) { switch($token) { case SPREADSHEET_EXCEL_WRITER_ADD: return $token; break; case SPREADSHEET_EXCEL_WRITER_SUB: return $token; break; case SPREADSHEET_EXCEL_WRITER_MUL: return $token; break; case SPREADSHEET_EXCEL_WRITER_DIV: return $token; break; case SPREADSHEET_EXCEL_WRITER_OPEN: return $token; break; case SPREADSHEET_EXCEL_WRITER_CLOSE: return $token; break; case SPREADSHEET_EXCEL_WRITER_COMA: return $token; break; case SPREADSHEET_EXCEL_WRITER_SEMICOLON: return $token; break; case SPREADSHEET_EXCEL_WRITER_GT: if ($this->_lookahead == '=') { // it's a GE token break; } return $token; break; case SPREADSHEET_EXCEL_WRITER_LT: // it's a LE or a NE token if (($this->_lookahead == '=') or ($this->_lookahead == '>')) { break; } return $token; break; case SPREADSHEET_EXCEL_WRITER_GE: return $token; break; case SPREADSHEET_EXCEL_WRITER_LE: return $token; break; case SPREADSHEET_EXCEL_WRITER_EQ: return $token; break; case SPREADSHEET_EXCEL_WRITER_NE: return $token; break; default: // if it's a reference if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and !ereg("[0-9]",$this->_lookahead) and ($this->_lookahead != ':') and ($this->_lookahead != '.') and ($this->_lookahead != '!')) { return $token; } // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and !ereg("[0-9]",$this->_lookahead) and ($this->_lookahead != ':') and ($this->_lookahead != '.')) { return $token; } // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$token) and !ereg("[0-9]",$this->_lookahead) and ($this->_lookahead != ':') and ($this->_lookahead != '.')) { return $token; } // if it's a range (A1:A2) elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and !ereg("[0-9]",$this->_lookahead)) { return $token; } // if it's a range (A1..A2) elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and !ereg("[0-9]",$this->_lookahead)) { return $token; } // If it's an external range like Sheet1!A1 or Sheet1:Sheet2!A1:B2 elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and !ereg("[0-9]",$this->_lookahead)) { return $token; } // If it's an external range like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2 elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$token) and !ereg("[0-9]",$this->_lookahead)) { return $token; } // If it's a number (check that it's not a sheet name or range) elseif (is_numeric($token) and (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and ($this->_lookahead != '!') and ($this->_lookahead != ':')) { return $token; } // If it's a string (of maximum 255 characters) elseif (ereg("^\"[^\"]{0,255}\"$",$token)) { return $token; } // if it's a function call elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$token) and ($this->_lookahead == "(")) { return $token; } return ''; } } /** * The parsing method. It parses a formula. * * @access public * @param string $formula The formula to parse, without the initial equal * sign (=). * @return mixed true on success, PEAR_Error on failure */ function parse($formula) { $this->_current_char = 0; $this->_formula = $formula; $this->_lookahead = $formula{1}; $this->_advance(); $this->_parse_tree = $this->_condition(); if (PEAR::isError($this->_parse_tree)) { return $this->_parse_tree; } return true; } /** * It parses a condition. It assumes the following rule: * Cond -> Expr [(">" | "<") Expr] * * @access private * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure */ function _condition() { $result = $this->_expression(); if (PEAR::isError($result)) { return $result; } if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgLT', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgGT', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgLE', $result, $result2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -