diff --git a/CHANGELOG.md b/CHANGELOG.md index 7940a6a29b..1b41ac2854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. ### Fixed +- Correctly handle absolute A1 references when converting to R1C1 format [PR #2060](https://github.com/PHPOffice/PhpSpreadsheet/pull/2060) - Correct default fill style for conditional without a pattern defined [Issue #2035](https://github.com/PHPOffice/PhpSpreadsheet/issues/2035) [PR #2050](https://github.com/PHPOffice/PhpSpreadsheet/pull/2050) - Fixed issue where array key check for existince before accessing arrays in Xlsx.php. [PR #1970](https://github.com/PHPOffice/PhpSpreadsheet/pull/1970) - Fixed issue with quoted strings in number format mask rendered with toFormattedString() [Issue 1972#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1972) [PR #1978](https://github.com/PHPOffice/PhpSpreadsheet/pull/1978) diff --git a/src/PhpSpreadsheet/Cell/AddressHelper.php b/src/PhpSpreadsheet/Cell/AddressHelper.php index b0e34e253c..632c046fdd 100644 --- a/src/PhpSpreadsheet/Cell/AddressHelper.php +++ b/src/PhpSpreadsheet/Cell/AddressHelper.php @@ -102,14 +102,23 @@ public static function convertToR1C1( ?int $currentRowNumber = null, ?int $currentColumnNumber = null ): string { - $validityCheck = preg_match('/^\$?([A-Z]{1,3})\$?(\d{1,7})$/i', $address, $cellReference); + $validityCheck = preg_match(Coordinate::A1_COORDINATE_REGEX, $address, $cellReference); if ($validityCheck === 0) { throw new Exception('Invalid A1-format Cell Reference'); } - $columnId = Coordinate::columnIndexFromString($cellReference[1]); - $rowId = (int) $cellReference[2]; + $columnId = Coordinate::columnIndexFromString($cellReference['col_ref']); + if ($cellReference['absolute_col'] === '$') { + // Column must be absolute address + $currentColumnNumber = null; + } + + $rowId = (int) $cellReference['row_ref']; + if ($cellReference['absolute_row'] === '$') { + // Row must be absolute address + $currentRowNumber = null; + } if ($currentRowNumber !== null) { if ($rowId === $currentRowNumber) { diff --git a/src/PhpSpreadsheet/Cell/Coordinate.php b/src/PhpSpreadsheet/Cell/Coordinate.php index 0b3917f265..58d2573e66 100644 --- a/src/PhpSpreadsheet/Cell/Coordinate.php +++ b/src/PhpSpreadsheet/Cell/Coordinate.php @@ -13,6 +13,8 @@ */ abstract class Coordinate { + public const A1_COORDINATE_REGEX = '/^(?\$?)(?[A-Z]{1,3})(?\$?)(?\d{1,7})$/i'; + /** * Default range variable constant. * @@ -29,8 +31,8 @@ abstract class Coordinate */ public static function coordinateFromString($pCoordinateString) { - if (preg_match('/^([$]?[A-Z]{1,3})([$]?\\d{1,7})$/', $pCoordinateString, $matches)) { - return [$matches[1], $matches[2]]; + if (preg_match(self::A1_COORDINATE_REGEX, $pCoordinateString, $matches)) { + return [$matches['absolute_col'] . $matches['col_ref'], $matches['absolute_row'] . $matches['row_ref']]; } elseif (self::coordinateIsRange($pCoordinateString)) { throw new Exception('Cell coordinate string can not be a range of cells'); } elseif ($pCoordinateString == '') { diff --git a/tests/data/Cell/A1ConversionToR1C1Relative.php b/tests/data/Cell/A1ConversionToR1C1Relative.php index 76a6aee879..dd9b23918f 100644 --- a/tests/data/Cell/A1ConversionToR1C1Relative.php +++ b/tests/data/Cell/A1ConversionToR1C1Relative.php @@ -2,18 +2,33 @@ return [ ['R[2]C[2]', 'O18', 16, 13], + ['R18C15', '$O$18', 16, 13], ['R[-2]C[2]', 'O14', 16, 13], + ['R[-2]C15', '$O14', 16, 13], ['R[2]C[-2]', 'K18', 16, 13], + ['R18C[-2]', 'K$18', 16, 13], ['R[-2]C[-2]', 'K14', 16, 13], ['RC[3]', 'P16', 16, 13], + ['R16C[3]', 'P$16', 16, 13], ['RC[-3]', 'J16', 16, 13], + ['RC10', '$J16', 16, 13], ['R[4]C', 'M20', 16, 13], + ['R[4]C13', '$M20', 16, 13], ['R[-4]C', 'M12', 16, 13], + ['R12C', 'M$12', 16, 13], ['RC', 'E5', 5, 5], + ['R5C5', '$E$5', 5, 5], ['R5C', 'E5', null, 5], + ['R5C5', '$E5', null, 5], + ['R5C', 'E$5', null, 5], ['RC5', 'E5', 5, null], + ['RC5', '$E5', 5, null], + ['R5C5', 'E$5', 5, null], ['R5C[2]', 'E5', null, 3], + ['R5C5', '$E5', null, 3], + ['R5C[2]', 'E$5', null, 3], ['R[2]C5', 'E5', 3, null], + ['R5C5', '$E$5', 3, null], ['R5C[-2]', 'E5', null, 7], ['R[-2]C5', 'E5', 7, null], ];