Merge pull request #2751 from PHPOffice/CalcEngine-Bugfix-Row-Column-Ranges
Resolve Calculation Engine bug with row and column ranges being identified as named ranges
This commit is contained in:
commit
de173d4705
|
|
@ -4178,7 +4178,10 @@ class Calculation
|
||||||
$testPrevOp = $stack->last(1);
|
$testPrevOp = $stack->last(1);
|
||||||
if ($testPrevOp !== null && $testPrevOp['value'] === ':') {
|
if ($testPrevOp !== null && $testPrevOp['value'] === ':') {
|
||||||
$stackItemType = 'Cell Reference';
|
$stackItemType = 'Cell Reference';
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
!is_numeric($val) &&
|
||||||
|
((ctype_alpha($val) === false || strlen($val) > 3)) &&
|
||||||
(preg_match('/^' . self::CALCULATION_REGEXP_DEFINEDNAME . '$/mui', $val) !== false) &&
|
(preg_match('/^' . self::CALCULATION_REGEXP_DEFINEDNAME . '$/mui', $val) !== false) &&
|
||||||
($this->spreadsheet->getNamedRange($val) !== null)
|
($this->spreadsheet->getNamedRange($val) !== null)
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
|
||||||
|
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
|
use PhpOffice\PhpSpreadsheet\NamedRange;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class ParseFormulaTest extends TestCase
|
class ParseFormulaTest extends TestCase
|
||||||
|
|
@ -12,7 +14,11 @@ class ParseFormulaTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testParseOperations(array $expectedStack, string $formula): void
|
public function testParseOperations(array $expectedStack, string $formula): void
|
||||||
{
|
{
|
||||||
$parser = Calculation::getInstance();
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$spreadsheet->addNamedRange(new NamedRange('GROUP1', $spreadsheet->getActiveSheet(), 'B2:D4'));
|
||||||
|
$spreadsheet->addNamedRange(new NamedRange('GROUP2', $spreadsheet->getActiveSheet(), 'D4:F6'));
|
||||||
|
|
||||||
|
$parser = Calculation::getInstance($spreadsheet);
|
||||||
$stack = $parser->parseFormula($formula);
|
$stack = $parser->parseFormula($formula);
|
||||||
self::assertSame($expectedStack, $stack);
|
self::assertSame($expectedStack, $stack);
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +86,36 @@ class ParseFormulaTest extends TestCase
|
||||||
],
|
],
|
||||||
'=-DEFINED_NAME%',
|
'=-DEFINED_NAME%',
|
||||||
],
|
],
|
||||||
|
'Integer Numbers with Operator' => [
|
||||||
|
[
|
||||||
|
['type' => 'Value', 'value' => 2, 'reference' => null],
|
||||||
|
['type' => 'Value', 'value' => 3, 'reference' => null],
|
||||||
|
['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=2*3',
|
||||||
|
],
|
||||||
|
'Float Numbers with Operator' => [
|
||||||
|
[
|
||||||
|
['type' => 'Value', 'value' => 2.5, 'reference' => null],
|
||||||
|
['type' => 'Value', 'value' => 3.5, 'reference' => null],
|
||||||
|
['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=2.5*3.5',
|
||||||
|
],
|
||||||
|
'Strings with Operator' => [
|
||||||
|
[
|
||||||
|
['type' => 'Value', 'value' => '"HELLO"', 'reference' => null],
|
||||||
|
['type' => 'Value', 'value' => '"WORLD"', 'reference' => null],
|
||||||
|
['type' => 'Binary Operator', 'value' => '&', 'reference' => null],
|
||||||
|
],
|
||||||
|
'="HELLO"&"WORLD"',
|
||||||
|
],
|
||||||
|
'Error' => [
|
||||||
|
[
|
||||||
|
['type' => 'Value', 'value' => '#DIV0!', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=#DIV0!',
|
||||||
|
],
|
||||||
'Cell Range' => [
|
'Cell Range' => [
|
||||||
[
|
[
|
||||||
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
||||||
|
|
@ -88,6 +124,16 @@ class ParseFormulaTest extends TestCase
|
||||||
],
|
],
|
||||||
'=A1:C3',
|
'=A1:C3',
|
||||||
],
|
],
|
||||||
|
'Chained Cell Range' => [
|
||||||
|
[
|
||||||
|
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
||||||
|
['type' => 'Cell Reference', 'value' => 'C3', 'reference' => 'C3'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
['type' => 'Cell Reference', 'value' => 'E5', 'reference' => 'E5'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=A1:C3:E5',
|
||||||
|
],
|
||||||
'Cell Range Intersection' => [
|
'Cell Range Intersection' => [
|
||||||
[
|
[
|
||||||
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
||||||
|
|
@ -100,6 +146,40 @@ class ParseFormulaTest extends TestCase
|
||||||
],
|
],
|
||||||
'=A1:C3 B2:D4',
|
'=A1:C3 B2:D4',
|
||||||
],
|
],
|
||||||
|
'Row Range' => [
|
||||||
|
[
|
||||||
|
['type' => 'Row Reference', 'value' => 'A2', 'reference' => 'A2'],
|
||||||
|
['type' => 'Row Reference', 'value' => 'XFD3', 'reference' => 'XFD3'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=2:3',
|
||||||
|
],
|
||||||
|
'Column Range' => [
|
||||||
|
[
|
||||||
|
['type' => 'Column Reference', 'value' => 'B1', 'reference' => 'B1'],
|
||||||
|
['type' => 'Column Reference', 'value' => 'C1048576', 'reference' => 'C1048576'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=B:C',
|
||||||
|
],
|
||||||
|
'Range with Defined Names' => [
|
||||||
|
[
|
||||||
|
['type' => 'Defined Name', 'value' => 'GROUP1', 'reference' => 'GROUP1'],
|
||||||
|
['type' => 'Defined Name', 'value' => 'D4', 'reference' => 'GROUP2'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
['type' => 'Defined Name', 'value' => 'F6', 'reference' => 'GROUP2'],
|
||||||
|
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=GROUP1:GROUP2',
|
||||||
|
],
|
||||||
|
'Named Range with Binary Operator' => [
|
||||||
|
[
|
||||||
|
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_1', 'reference' => 'DEFINED_NAME_1'],
|
||||||
|
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_2', 'reference' => 'DEFINED_NAME_2'],
|
||||||
|
['type' => 'Binary Operator', 'value' => '/', 'reference' => null],
|
||||||
|
],
|
||||||
|
'=DEFINED_NAME_1/DEFINED_NAME_2',
|
||||||
|
],
|
||||||
'Named Range Intersection' => [
|
'Named Range Intersection' => [
|
||||||
[
|
[
|
||||||
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_1', 'reference' => 'DEFINED_NAME_1'],
|
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_1', 'reference' => 'DEFINED_NAME_1'],
|
||||||
|
|
@ -108,6 +188,22 @@ class ParseFormulaTest extends TestCase
|
||||||
],
|
],
|
||||||
'=DEFINED_NAME_1 DEFINED_NAME_2',
|
'=DEFINED_NAME_1 DEFINED_NAME_2',
|
||||||
],
|
],
|
||||||
|
// 'Structured Reference Arithmetic' => [
|
||||||
|
// [
|
||||||
|
// ['type' => 'Structured Reference', 'value' => '[@Quantity]', 'reference' => null],
|
||||||
|
// ['type' => 'Structured Reference', 'value' => '[@[Unit Price]]', 'reference' => null],
|
||||||
|
// ['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
|
||||||
|
// ],
|
||||||
|
// '=[@Quantity]*[@[Unit Price]]',
|
||||||
|
// ],
|
||||||
|
// 'Structured Reference Intersection' => [
|
||||||
|
// [
|
||||||
|
// ['type' => 'Structured Reference', 'value' => 'DeptSales[[Sales Person]:[Sales Amount]]', 'reference' => null],
|
||||||
|
// ['type' => 'Structured Reference', 'value' => 'DeptSales[[Region]:[% Commission]]', 'reference' => null],
|
||||||
|
// ['type' => 'Binary Operator', 'value' => '∩', 'reference' => null],
|
||||||
|
// ],
|
||||||
|
// '=DeptSales[[Sales Person]:[Sales Amount]] DeptSales[[Region]:[% Commission]]',
|
||||||
|
// ],
|
||||||
// 'Cell Range Union' => [
|
// 'Cell Range Union' => [
|
||||||
// [
|
// [
|
||||||
// ['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
// ['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue