Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 16 additions & 3 deletions src/PhpSpreadsheet/Cell/AddressHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,27 @@ 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('/^(\$?[A-Z]{1,3})(\$?\d{1,7})$/i', $address, $cellReference);

if ($validityCheck === 0) {
throw new Exception('Invalid A1-format Cell Reference');
}

$columnId = Coordinate::columnIndexFromString($cellReference[1]);
$rowId = (int) $cellReference[2];
if ($cellReference[1][0] === '$') {
$columnId = Coordinate::columnIndexFromString(substr($cellReference[1], 1));
Copy link
Member

@MarkBaker MarkBaker May 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be easier to extract the $ for absolutes, the column address and row id directly through individual capture groups in the regexp rather than using substring? Then you can also eliminate the else condition in these if statements, which reduces the complexity of the code for path coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I originally went this way to not increase the complexity of the regex, but I think your way is cleaner. I'll push an update today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed that change now. Much cleaner 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those changes to the regex don't add any significant cost to execution, as you're already executing the regex anyway; but do eliminate the substr() function calls.

The only thing I'd be tempted to change now would be to use named capture groups in the regex, so you could reference

$rowId = (int) $cellReference['row_id'];

or

if ($cellReference['absolute_column_ref'] === '$') {

as associative rather than enumerated, which adds to the readability of the code.

I've only recently started using named capture groups myself. It gives the benefit of improved readability of purpose, but It does add to the complexity of the expression. I can understand if you wouldn't want to use them though.

One last change I'd suggest would be to extract the regex to a class constant, which can then be made public, because potentially there's other places in the codebase that could use it (such as the coordinateFromString() method in Cell\Coordinate... it might be better located there as a public class constant anyway).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that named groups are much more readable, I just stuck with non-named to match the existing code style.

I've updated it to use named groups and also moved the regex into a constant and reused it in Cell\Coordinate. Which is outside of scope for this PR, but I think the regexes should be reused constants which will minimize future bugs. Happy to undo this change if you want, but the tests still pass so it should be fine?

// Column must be absolute address
$currentColumnNumber = null;
} else {
$columnId = Coordinate::columnIndexFromString($cellReference[1]);
}

if ($cellReference[2][0] === '$') {
$rowId = (int) substr($cellReference[2], 1);
// Row must be absolute address
$currentRowNumber = null;
} else {
$rowId = (int) $cellReference[2];
}

if ($currentRowNumber !== null) {
if ($rowId === $currentRowNumber) {
Expand Down
15 changes: 15 additions & 0 deletions tests/data/Cell/A1ConversionToR1C1Relative.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
];