Adjust calc engine identification of quoted worksheet names to fix bug with multiple quoted worksheets in formula

This commit is contained in:
MarkBaker 2022-06-17 12:30:04 +02:00
parent adf4531c99
commit 23e207ccb4
2 changed files with 55 additions and 7 deletions

View File

@ -33,17 +33,17 @@ class Calculation
// Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?([\p{L}][\p{L}\p{N}\.]*)[\s]*\(';
// Cell reference (cell or range of cells, with or without a sheet reference)
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'\')+?\')|(\"(?:[^\"]|\"\")+?\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])';
const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])';
// Cell reference (with or without a sheet reference) ensuring absolute/relative
const CALCULATION_REGEXP_CELLREF_RELATIVE = '((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'\')+?\')|(\"(?:[^\"]|\"\")+?\"))!)?(\$?\b[a-z]{1,3})(\$?\d{1,7})(?![\w.])';
const CALCULATION_REGEXP_COLUMN_RANGE = '(((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'\')+?\')|(\".(?:[^\"]|\"\")?\"))!)?(\$?[a-z]{1,3})):(?![.*])';
const CALCULATION_REGEXP_ROW_RANGE = '(((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'\')+?\')|(\"(?:[^\"]|\"\")+?\"))!)?(\$?[1-9][0-9]{0,6})):(?![.*])';
const CALCULATION_REGEXP_CELLREF_RELATIVE = '((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?(\$?\b[a-z]{1,3})(\$?\d{1,7})(?![\w.])';
const CALCULATION_REGEXP_COLUMN_RANGE = '(((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\".(?:[^\"]|\"[^!])?\"))!)?(\$?[a-z]{1,3})):(?![.*])';
const CALCULATION_REGEXP_ROW_RANGE = '(((([^\s\(,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?(\$?[1-9][0-9]{0,6})):(?![.*])';
// Cell reference (with or without a sheet reference) ensuring absolute/relative
// Cell ranges ensuring absolute/relative
const CALCULATION_REGEXP_COLUMNRANGE_RELATIVE = '(\$?[a-z]{1,3}):(\$?[a-z]{1,3})';
const CALCULATION_REGEXP_ROWRANGE_RELATIVE = '(\$?\d{1,7}):(\$?\d{1,7})';
// Defined Names: Named Range of cells, or Named Formulae
const CALCULATION_REGEXP_DEFINEDNAME = '((([^\s,!&%^\/\*\+<>=-]*)|(\'(?:[^\']|\'\')+?\')|(\"(?:[^\"]|\"\")+?\"))!)?([_\p{L}][_\p{L}\p{N}\.]*)';
const CALCULATION_REGEXP_DEFINEDNAME = '((([^\s,!&%^\/\*\+<>=-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?([_\p{L}][_\p{L}\p{N}\.]*)';
// Error
const CALCULATION_REGEXP_ERROR = '\#[A-Z][A-Z0_\/]*[!\?]?';

View File

@ -174,6 +174,30 @@ class ParseFormulaTest extends TestCase
],
"=MIN('sheet1'!A:A) + 'sheet1'!A1",
],
'Combined Cell Reference and Column Range with quote' => [
[
['type' => 'Column Reference', 'value' => "'Mark''s sheet1'!A1", 'reference' => "'Mark''s sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark''s sheet1'!A1048576", 'reference' => "'Mark''s sheet1'!A1048576"],
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
['type' => 'Operand Count for Function MIN()', 'value' => 1, 'reference' => null],
['type' => 'Function', 'value' => 'MIN(', 'reference' => null],
['type' => 'Cell Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Binary Operator', 'value' => '+', 'reference' => null],
],
"=MIN('Mark''s sheet1'!A:A) + 'Mark''s sheet1'!A1",
],
'Combined Cell Reference and Column Range with unescaped quote' => [
[
['type' => 'Column Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark's sheet1'!A1048576", 'reference' => "'Mark's sheet1'!A1048576"],
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
['type' => 'Operand Count for Function MIN()', 'value' => 1, 'reference' => null],
['type' => 'Function', 'value' => 'MIN(', 'reference' => null],
['type' => 'Cell Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Binary Operator', 'value' => '+', 'reference' => null],
],
"=MIN('Mark's sheet1'!A:A) + 'Mark's sheet1'!A1",
],
'Combined Column Range and Cell Reference' => [
[
['type' => 'Cell Reference', 'value' => "'sheet1'!A1", 'reference' => "'sheet1'!A1"],
@ -186,6 +210,30 @@ class ParseFormulaTest extends TestCase
],
"='sheet1'!A1 + MIN('sheet1'!A:A)",
],
'Combined Column Range and Cell Reference with quote' => [
[
['type' => 'Cell Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark''s sheet1'!A1", 'reference' => "'Mark''s sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark''s sheet1'!A1048576", 'reference' => "'Mark''s sheet1'!A1048576"],
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
['type' => 'Operand Count for Function MIN()', 'value' => 1, 'reference' => null],
['type' => 'Function', 'value' => 'MIN(', 'reference' => null],
['type' => 'Binary Operator', 'value' => '+', 'reference' => null],
],
"='Mark''s sheet1'!A1 + MIN('Mark''s sheet1'!A:A)",
],
'Combined Column Range and Cell Reference with unescaped quote' => [
[
['type' => 'Cell Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark's sheet1'!A1", 'reference' => "'Mark's sheet1'!A1"],
['type' => 'Column Reference', 'value' => "'Mark's sheet1'!A1048576", 'reference' => "'Mark's sheet1'!A1048576"],
['type' => 'Binary Operator', 'value' => ':', 'reference' => null],
['type' => 'Operand Count for Function MIN()', 'value' => 1, 'reference' => null],
['type' => 'Function', 'value' => 'MIN(', 'reference' => null],
['type' => 'Binary Operator', 'value' => '+', 'reference' => null],
],
"='Mark's sheet1'!A1 + MIN('Mark's sheet1'!A:A)",
],
'Range with Defined Names' => [
[
['type' => 'Defined Name', 'value' => 'GROUP1', 'reference' => 'GROUP1'],