Skip to content

Commit de173d4

Browse files
authored
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
2 parents 4a28fd6 + 716964e commit de173d4

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

src/PhpSpreadsheet/Calculation/Calculation.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4178,7 +4178,10 @@ private function internalParseFormula($formula, ?Cell $cell = null)
41784178
$testPrevOp = $stack->last(1);
41794179
if ($testPrevOp !== null && $testPrevOp['value'] === ':') {
41804180
$stackItemType = 'Cell Reference';
4181+
41814182
if (
4183+
!is_numeric($val) &&
4184+
((ctype_alpha($val) === false || strlen($val) > 3)) &&
41824185
(preg_match('/^' . self::CALCULATION_REGEXP_DEFINEDNAME . '$/mui', $val) !== false) &&
41834186
($this->spreadsheet->getNamedRange($val) !== null)
41844187
) {

tests/PhpSpreadsheetTests/Calculation/ParseFormulaTest.php

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
44

55
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6+
use PhpOffice\PhpSpreadsheet\NamedRange;
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
68
use PHPUnit\Framework\TestCase;
79

810
class ParseFormulaTest extends TestCase
@@ -12,7 +14,11 @@ class ParseFormulaTest extends TestCase
1214
*/
1315
public function testParseOperations(array $expectedStack, string $formula): void
1416
{
15-
$parser = Calculation::getInstance();
17+
$spreadsheet = new Spreadsheet();
18+
$spreadsheet->addNamedRange(new NamedRange('GROUP1', $spreadsheet->getActiveSheet(), 'B2:D4'));
19+
$spreadsheet->addNamedRange(new NamedRange('GROUP2', $spreadsheet->getActiveSheet(), 'D4:F6'));
20+
21+
$parser = Calculation::getInstance($spreadsheet);
1622
$stack = $parser->parseFormula($formula);
1723
self::assertSame($expectedStack, $stack);
1824
}
@@ -80,6 +86,36 @@ public function providerBinaryOperations(): array
8086
],
8187
'=-DEFINED_NAME%',
8288
],
89+
'Integer Numbers with Operator' => [
90+
[
91+
['type' => 'Value', 'value' => 2, 'reference' => null],
92+
['type' => 'Value', 'value' => 3, 'reference' => null],
93+
['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
94+
],
95+
'=2*3',
96+
],
97+
'Float Numbers with Operator' => [
98+
[
99+
['type' => 'Value', 'value' => 2.5, 'reference' => null],
100+
['type' => 'Value', 'value' => 3.5, 'reference' => null],
101+
['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
102+
],
103+
'=2.5*3.5',
104+
],
105+
'Strings with Operator' => [
106+
[
107+
['type' => 'Value', 'value' => '"HELLO"', 'reference' => null],
108+
['type' => 'Value', 'value' => '"WORLD"', 'reference' => null],
109+
['type' => 'Binary Operator', 'value' => '&', 'reference' => null],
110+
],
111+
'="HELLO"&"WORLD"',
112+
],
113+
'Error' => [
114+
[
115+
['type' => 'Value', 'value' => '#DIV0!', 'reference' => null],
116+
],
117+
'=#DIV0!',
118+
],
83119
'Cell Range' => [
84120
[
85121
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
@@ -88,6 +124,16 @@ public function providerBinaryOperations(): array
88124
],
89125
'=A1:C3',
90126
],
127+
'Chained Cell Range' => [
128+
[
129+
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
130+
['type' => 'Cell Reference', 'value' => 'C3', 'reference' => 'C3'],
131+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
132+
['type' => 'Cell Reference', 'value' => 'E5', 'reference' => 'E5'],
133+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
134+
],
135+
'=A1:C3:E5',
136+
],
91137
'Cell Range Intersection' => [
92138
[
93139
['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],
@@ -100,6 +146,40 @@ public function providerBinaryOperations(): array
100146
],
101147
'=A1:C3 B2:D4',
102148
],
149+
'Row Range' => [
150+
[
151+
['type' => 'Row Reference', 'value' => 'A2', 'reference' => 'A2'],
152+
['type' => 'Row Reference', 'value' => 'XFD3', 'reference' => 'XFD3'],
153+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
154+
],
155+
'=2:3',
156+
],
157+
'Column Range' => [
158+
[
159+
['type' => 'Column Reference', 'value' => 'B1', 'reference' => 'B1'],
160+
['type' => 'Column Reference', 'value' => 'C1048576', 'reference' => 'C1048576'],
161+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
162+
],
163+
'=B:C',
164+
],
165+
'Range with Defined Names' => [
166+
[
167+
['type' => 'Defined Name', 'value' => 'GROUP1', 'reference' => 'GROUP1'],
168+
['type' => 'Defined Name', 'value' => 'D4', 'reference' => 'GROUP2'],
169+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
170+
['type' => 'Defined Name', 'value' => 'F6', 'reference' => 'GROUP2'],
171+
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
172+
],
173+
'=GROUP1:GROUP2',
174+
],
175+
'Named Range with Binary Operator' => [
176+
[
177+
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_1', 'reference' => 'DEFINED_NAME_1'],
178+
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_2', 'reference' => 'DEFINED_NAME_2'],
179+
['type' => 'Binary Operator', 'value' => '/', 'reference' => null],
180+
],
181+
'=DEFINED_NAME_1/DEFINED_NAME_2',
182+
],
103183
'Named Range Intersection' => [
104184
[
105185
['type' => 'Defined Name', 'value' => 'DEFINED_NAME_1', 'reference' => 'DEFINED_NAME_1'],
@@ -108,6 +188,22 @@ public function providerBinaryOperations(): array
108188
],
109189
'=DEFINED_NAME_1 DEFINED_NAME_2',
110190
],
191+
// 'Structured Reference Arithmetic' => [
192+
// [
193+
// ['type' => 'Structured Reference', 'value' => '[@Quantity]', 'reference' => null],
194+
// ['type' => 'Structured Reference', 'value' => '[@[Unit Price]]', 'reference' => null],
195+
// ['type' => 'Binary Operator', 'value' => '*', 'reference' => null],
196+
// ],
197+
// '=[@Quantity]*[@[Unit Price]]',
198+
// ],
199+
// 'Structured Reference Intersection' => [
200+
// [
201+
// ['type' => 'Structured Reference', 'value' => 'DeptSales[[Sales Person]:[Sales Amount]]', 'reference' => null],
202+
// ['type' => 'Structured Reference', 'value' => 'DeptSales[[Region]:[% Commission]]', 'reference' => null],
203+
// ['type' => 'Binary Operator', 'value' => '∩', 'reference' => null],
204+
// ],
205+
// '=DeptSales[[Sales Person]:[Sales Amount]] DeptSales[[Region]:[% Commission]]',
206+
// ],
111207
// 'Cell Range Union' => [
112208
// [
113209
// ['type' => 'Cell Reference', 'value' => 'A1', 'reference' => 'A1'],

0 commit comments

Comments
 (0)