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