| 1 |
<?php |
| 2 |
|
| 3 |
namespace FluentCart\OpenSpout\Reader\XLSX\Helper; |
| 4 |
|
| 5 |
use FluentCart\OpenSpout\Common\Exception\InvalidArgumentException; |
| 6 |
/** |
| 7 |
* This class provides helper functions when working with cells. |
| 8 |
*/ |
| 9 |
class CellHelper |
| 10 |
{ |
| 11 |
// Using ord() is super slow... Using a pre-computed hash table instead. |
| 12 |
private static $columnLetterToIndexMapping = ['A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25]; |
| 13 |
/** |
| 14 |
* Returns the base 10 column index associated to the cell index (base 26). |
| 15 |
* Excel uses A to Z letters for column indexing, where A is the 1st column, |
| 16 |
* Z is the 26th and AA is the 27th. |
| 17 |
* The mapping is zero based, so that A1 maps to 0, B2 maps to 1, Z13 to 25 and AA4 to 26. |
| 18 |
* |
| 19 |
* @param string $cellIndex The Excel cell index ('A1', 'BC13', ...) |
| 20 |
* |
| 21 |
* @throws \OpenSpout\Common\Exception\InvalidArgumentException When the given cell index is invalid |
| 22 |
* |
| 23 |
* @return int |
| 24 |
*/ |
| 25 |
public static function getColumnIndexFromCellIndex($cellIndex) |
| 26 |
{ |
| 27 |
if (!self::isValidCellIndex($cellIndex)) { |
| 28 |
throw new InvalidArgumentException('Cannot get column index from an invalid cell index.'); |
| 29 |
} |
| 30 |
$columnIndex = 0; |
| 31 |
// Remove row information |
| 32 |
$columnLetters = \preg_replace('/\\d/', '', $cellIndex); |
| 33 |
// strlen() is super slow too... Using isset() is way faster and not too unreadable, |
| 34 |
// since we checked before that there are between 1 and 3 letters. |
| 35 |
$columnLength = isset($columnLetters[1]) ? isset($columnLetters[2]) ? 3 : 2 : 1; |
| 36 |
// Looping over the different letters of the column is slower than this method. |
| 37 |
// Also, not using the pow() function because it's slooooow... |
| 38 |
switch ($columnLength) { |
| 39 |
case 1: |
| 40 |
$columnIndex = self::$columnLetterToIndexMapping[$columnLetters]; |
| 41 |
break; |
| 42 |
case 2: |
| 43 |
$firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 26; |
| 44 |
$secondLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[1]]; |
| 45 |
$columnIndex = $firstLetterIndex + $secondLetterIndex; |
| 46 |
break; |
| 47 |
case 3: |
| 48 |
$firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 676; |
| 49 |
$secondLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[1]] + 1) * 26; |
| 50 |
$thirdLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[2]]; |
| 51 |
$columnIndex = $firstLetterIndex + $secondLetterIndex + $thirdLetterIndex; |
| 52 |
break; |
| 53 |
} |
| 54 |
return $columnIndex; |
| 55 |
} |
| 56 |
/** |
| 57 |
* Returns whether a cell index is valid, in an Excel world. |
| 58 |
* To be valid, the cell index should start with capital letters and be followed by numbers. |
| 59 |
* There can only be 3 letters, as there can only be 16,384 rows, which is equivalent to 'XFE'. |
| 60 |
* |
| 61 |
* @param string $cellIndex The Excel cell index ('A1', 'BC13', ...) |
| 62 |
* |
| 63 |
* @return bool |
| 64 |
*/ |
| 65 |
protected static function isValidCellIndex($cellIndex) |
| 66 |
{ |
| 67 |
return 1 === \preg_match('/^[A-Z]{1,3}\\d+$/', $cellIndex); |
| 68 |
} |
| 69 |
} |
| 70 |
|