@@ -380,21 +380,71 @@ public function rowsIterator(int $sheetNumber): \Traversable
380380 }
381381
382382 /**
383- * Sort cells within the same line, such as B3, AA3. Compare only the column part.
384- * @param $ref1 A cell reference such as B3
385- * @param $ref1 A cell reference such as AA3
383+ * Produce an array from a worksheet, indexed by column name (like `AB`) first, then line (like `12`).
384+ * Only the existing lines and cells are included.
385+ * @return array<string,array<int,null|string>> An array that can be access like `$array['AB'][12]`
386+ */
387+ public function readArray (int $ sheetNumber ): array
388+ {
389+ $ table = [];
390+ foreach ($ this ->rowsIterator ($ sheetNumber ) as $ row ) {
391+ foreach ($ row ->cellsIterator () as $ cell ) {
392+ $ table [$ cell ->column ()][$ row ->number ()] = $ cell ->readString ();
393+ }
394+ }
395+ return $ table ;
396+ }
397+
398+ /**
399+ * Produce an array from a worksheet, indexed by column header (like `columnName`) first, then line (like `12`),
400+ * having the column header defined in the first existing line of the spreadsheet.
401+ * Only the existing lines and cells are included.
402+ * @return array<string,array<int,null|string>> An array that can be access like `$array['columnName'][12]`
403+ */
404+ public function readArrayWithHeaders (int $ sheetNumber ): array
405+ {
406+ $ table = [];
407+ $ headers = [];
408+ $ firstRow = true ;
409+ foreach ($ this ->rowsIterator ($ sheetNumber ) as $ row ) {
410+ if ($ firstRow ) {
411+ foreach ($ row ->cellsIterator () as $ cell ) {
412+ $ headers [$ cell ->column ()] = $ cell ->readString ();
413+ }
414+ $ firstRow = false ;
415+ continue ;
416+ }
417+ foreach ($ row ->cellsIterator () as $ cell ) {
418+ $ header = $ headers [$ cell ->column ()] ?? $ cell ->column ();
419+ $ table [$ header ][$ row ->number ()] = $ cell ->readString ();
420+ }
421+ }
422+ return $ table ;
423+ }
424+
425+ /**
426+ * Sort cells (such as `B3`, `AA23`) on column first (such as `B`, `AA`) and then line (such as `3`, `23`).
427+ * @param $ref1 A cell reference such as `B3`
428+ * @param $ref1 A cell reference such as `AA23`
386429 * @return int -1 if $ref1 is before $ref2; 1 if $ref1 is greater than $ref2, and 0 if they are equal.
387- * @internal
388430 */
389- public static function _columnOrderCompare (string $ ref1 , string $ ref2 ): int
431+ public static function cellOrderCompare (string $ ref1 , string $ ref2 ): int
390432 {
391- $ pattern = '/[^A-Z]+/ ' ;
392- $ column1 = preg_replace ($ pattern , '' , $ ref1 ) ?? '' ;
393- $ column2 = preg_replace ($ pattern , '' , $ ref2 ) ?? '' ;
394- $ length1 = strlen ($ column1 );
395- $ length2 = strlen ($ column2 );
396- if ($ length1 !== $ length2 ) {
397- return $ length1 <=> $ length2 ;
433+ if (preg_match ('/^([A-Z]+)(\d+)$/ ' , $ ref1 , $ matches1 ) === 1 && preg_match ('/^([A-Z]+)(\d+)$/ ' , $ ref2 , $ matches2 ) === 1 ) {
434+ $ column1 = $ matches1 [1 ];
435+ $ column2 = $ matches2 [1 ];
436+ $ length1 = strlen ($ column1 );
437+ $ length2 = strlen ($ column2 );
438+ if ($ length1 !== $ length2 ) {
439+ return $ length1 <=> $ length2 ;
440+ }
441+ $ cmp = strcmp ($ column1 , $ column2 );
442+ if ($ cmp !== 0 ) {
443+ return $ cmp ;
444+ }
445+ $ line1 = (int )$ matches1 [2 ];
446+ $ line2 = (int )$ matches2 [2 ];
447+ return $ line1 <=> $ line2 ;
398448 }
399449 return strcmp ($ ref1 , $ ref2 );
400450 }
0 commit comments