-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Helper class for the conversion of cell addresses between A1 and R1C1…
… formats, and vice-versa (#1558) * Helper class for the conversion of cell addresses between A1 and R1C1 formats, and vice-versa
- Loading branch information
Mark Baker
authored
Jun 27, 2020
1 parent
10a4a95
commit a264caf
Showing
8 changed files
with
272 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
|
||
namespace PhpOffice\PhpSpreadsheet\Cell; | ||
|
||
use PhpOffice\PhpSpreadsheet\Exception; | ||
|
||
class AddressHelper | ||
{ | ||
/** | ||
* Converts an R1C1 format cell address to an A1 format cell address. | ||
*/ | ||
public static function convertToA1( | ||
string $address, | ||
int $currentRowNumber = 1, | ||
int $currentColumnNumber = 1 | ||
): string { | ||
$validityCheck = preg_match('/^(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))$/i', $address, $cellReference); | ||
|
||
if ($validityCheck === 0) { | ||
throw new Exception('Invalid R1C1-format Cell Reference'); | ||
} | ||
|
||
$rowReference = $cellReference[2]; | ||
// Empty R reference is the current row | ||
if ($rowReference === '') { | ||
$rowReference = (string) $currentRowNumber; | ||
} | ||
// Bracketed R references are relative to the current row | ||
if ($rowReference[0] === '[') { | ||
$rowReference = $currentRowNumber + trim($rowReference, '[]'); | ||
} | ||
$columnReference = $cellReference[4]; | ||
// Empty C reference is the current column | ||
if ($columnReference === '') { | ||
$columnReference = (string) $currentColumnNumber; | ||
} | ||
// Bracketed C references are relative to the current column | ||
if ($columnReference[0] === '[') { | ||
$columnReference = $currentColumnNumber + trim($columnReference, '[]'); | ||
} | ||
|
||
if ($columnReference <= 0 || $rowReference <= 0) { | ||
throw new Exception('Invalid R1C1-format Cell Reference, Value out of range'); | ||
} | ||
$A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference; | ||
|
||
return $A1CellReference; | ||
} | ||
|
||
/** | ||
* Converts an A1 format cell address to an R1C1 format cell address. | ||
* If $currentRowNumber or $currentColumnNumber are provided, then the R1C1 address will be formatted as a relative address. | ||
*/ | ||
public static function convertToR1C1( | ||
string $address, | ||
?int $currentRowNumber = null, | ||
?int $currentColumnNumber = null | ||
): string { | ||
$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 ($currentRowNumber !== null) { | ||
if ($rowId === $currentRowNumber) { | ||
$rowId = ''; | ||
} else { | ||
$rowId = '[' . ($rowId - $currentRowNumber) . ']'; | ||
} | ||
} | ||
|
||
if ($currentColumnNumber !== null) { | ||
if ($columnId === $currentColumnNumber) { | ||
$columnId = ''; | ||
} else { | ||
$columnId = '[' . ($columnId - $currentColumnNumber) . ']'; | ||
} | ||
} | ||
|
||
$R1C1Address = "R{$rowId}C{$columnId}"; | ||
|
||
return $R1C1Address; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<?php | ||
|
||
namespace PhpOffice\PhpSpreadsheetTests\Cell; | ||
|
||
use PhpOffice\PhpSpreadsheet\Cell\AddressHelper; | ||
use PhpOffice\PhpSpreadsheet\Exception; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class AddressHelperTest extends TestCase | ||
{ | ||
/** | ||
* @dataProvider providerR1C1ConversionToA1Absolute | ||
*/ | ||
public function testR1C1ConversionToA1Absolute(string $expectedValue, string $address): void | ||
{ | ||
$actualValue = AddressHelper::convertToA1($address); | ||
|
||
self::assertSame($expectedValue, $actualValue); | ||
} | ||
|
||
public function providerR1C1ConversionToA1Absolute() | ||
{ | ||
return require 'tests/data/Cell/R1C1ConversionToA1Absolute.php'; | ||
} | ||
|
||
/** | ||
* @dataProvider providerR1C1ConversionToA1Relative | ||
*/ | ||
public function testR1C1ConversionToA1Relative(string $expectedValue, string $address, ?int $row = null, ?int $column = null): void | ||
{ | ||
$args = [$address]; | ||
if ($row !== null) { | ||
$args[] = $row; | ||
} | ||
if ($column !== null) { | ||
$args[] = $column; | ||
} | ||
|
||
$actualValue = AddressHelper::convertToA1(...$args); | ||
|
||
self::assertSame($expectedValue, $actualValue); | ||
} | ||
|
||
public function providerR1C1ConversionToA1Relative() | ||
{ | ||
return require 'tests/data/Cell/R1C1ConversionToA1Relative.php'; | ||
} | ||
|
||
/** | ||
* @dataProvider providerR1C1ConversionToA1Exception | ||
*/ | ||
public function testR1C1ConversionToA1Exception(string $address): void | ||
{ | ||
$this->expectException(Exception::class); | ||
|
||
AddressHelper::convertToA1($address); | ||
} | ||
|
||
public function providerR1C1ConversionToA1Exception() | ||
{ | ||
return require 'tests/data/Cell/R1C1ConversionToA1Exception.php'; | ||
} | ||
|
||
/** | ||
* @dataProvider providerA1ConversionToR1C1Absolute | ||
*/ | ||
public function testA1ConversionToR1C1Absolute(string $expectedValue, string $address): void | ||
{ | ||
$actualValue = AddressHelper::convertToR1C1($address); | ||
|
||
self::assertSame($expectedValue, $actualValue); | ||
} | ||
|
||
public function providerA1ConversionToR1C1Absolute() | ||
{ | ||
return require 'tests/data/Cell/A1ConversionToR1C1Absolute.php'; | ||
} | ||
|
||
/** | ||
* @dataProvider providerA1ConversionToR1C1Relative | ||
*/ | ||
public function testA1ConversionToR1C1Relative(string $expectedValue, string $address, ?int $row = null, ?int $column = null): void | ||
{ | ||
$actualValue = AddressHelper::convertToR1C1($address, $row, $column); | ||
|
||
self::assertSame($expectedValue, $actualValue); | ||
} | ||
|
||
public function providerA1ConversionToR1C1Relative() | ||
{ | ||
return require 'tests/data/Cell/A1ConversionToR1C1Relative.php'; | ||
} | ||
|
||
/** | ||
* @dataProvider providerA1ConversionToR1C1Exception | ||
*/ | ||
public function testA1ConversionToR1C1Exception(string $address): void | ||
{ | ||
$this->expectException(Exception::class); | ||
|
||
AddressHelper::convertToR1C1($address); | ||
} | ||
|
||
public function providerA1ConversionToR1C1Exception() | ||
{ | ||
return require 'tests/data/Cell/A1ConversionToR1C1Exception.php'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
return [ | ||
['R1C1', 'A1'], | ||
['R1C1', '$A$1'], | ||
['R1C1', '$A1'], | ||
['R1C1', 'A$1'], | ||
['R2C2', 'B2'], | ||
['R5C12', 'L5'], | ||
['R1024C26', 'Z1024'], | ||
['R2048C27', 'AA2048'], | ||
['R4096C52', 'AZ4096'], | ||
['R8192C53', 'BA8192'], | ||
['R65535C256', 'IV65535'], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?php | ||
|
||
return [ | ||
['A11Y'], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
return [ | ||
['R[2]C[2]', 'O18', 16, 13], | ||
['R[-2]C[2]', 'O14', 16, 13], | ||
['R[2]C[-2]', 'K18', 16, 13], | ||
['R[-2]C[-2]', 'K14', 16, 13], | ||
['RC[3]', 'P16', 16, 13], | ||
['RC[-3]', 'J16', 16, 13], | ||
['R[4]C', 'M20', 16, 13], | ||
['R[-4]C', 'M12', 16, 13], | ||
['RC', 'E5', 5, 5], | ||
['R5C', 'E5', null, 5], | ||
['RC5', 'E5', 5, null], | ||
['R5C[2]', 'E5', null, 3], | ||
['R[2]C5', 'E5', 3, null], | ||
['R5C[-2]', 'E5', null, 7], | ||
['R[-2]C5', 'E5', 7, null], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
return [ | ||
['A1', 'R1C1'], | ||
['B2', 'R2C2'], | ||
['L5', 'R5C12'], | ||
['Z1024', 'R1024C26'], | ||
['AA2048', 'R2048C27'], | ||
['AZ4096', 'R4096C52'], | ||
['BA8192', 'R8192C53'], | ||
['IV65535', 'R65535C256'], | ||
['K1', 'RC11'], | ||
['A16', 'R16C'], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
return [ | ||
['RICE'], | ||
['R[-1]C'], | ||
['RC[-1]'], | ||
['R-1C'], | ||
['RC-1'], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<?php | ||
|
||
return [ | ||
['C3', 'R[2]C[2]'], | ||
['O18', 'R[2]C[2]', 16, 13], | ||
['O14', 'R[-2]C[2]', 16, 13], | ||
['K18', 'R[2]C[-2]', 16, 13], | ||
['K14', 'R[-2]C[-2]', 16, 13], | ||
['P16', 'RC[3]', 16, 13], | ||
['J16', 'RC[-3]', 16, 13], | ||
['M20', 'R[4]C', 16, 13], | ||
['M12', 'R[-4]C', 16, 13], | ||
['E5', 'RC', 5, 5], | ||
]; |