From a5d3b91817cd49480a02e6eb36276dfb95317ef6 Mon Sep 17 00:00:00 2001 From: Antony Date: Tue, 7 Feb 2023 10:43:29 +0000 Subject: [PATCH] Add ROW and COLUMN functions --- src/Range.js | 21 +++++++++++++++++++-- src/formulas-raw.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/1-basic-test.js | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/Range.js b/src/Range.js index a7dbf5c..fc44cd8 100644 --- a/src/Range.js +++ b/src/Range.js @@ -5,7 +5,7 @@ const int_2_col_str = require('./int_2_col_str.js'); const getSanitizedSheetName = require('./getSanitizedSheetName.js'); module.exports = function Range(str_expression, formula) { - this.calc = function() { + this.parse = function() { var range_expression, sheet_name, sheet; if (str_expression.indexOf('!') != -1) { var aux = str_expression.split('!'); @@ -22,12 +22,29 @@ module.exports = function Range(str_expression, formula) { var str_max_row = arr[1].replace(/^[A-Z]+/, ''); var max_row; if (str_max_row === '' && sheet['!ref']) { - str_max_row = sheet['!ref'].split(':')[1].replace(/^[A-Z]+/, ''); + str_max_row = (sheet['!ref'].includes(':') ? sheet['!ref'].split(':')[1] : sheet['!ref']).replace(/^[A-Z]+/, ''); } // the max is 1048576, but TLE max_row = parseInt(str_max_row == '' ? '500000' : str_max_row, 10); var min_col = col_str_2_int(arr[0]); var max_col = col_str_2_int(arr[1]); + return { + sheet_name: sheet_name, + sheet: sheet, + min_row: min_row, + min_col: min_col, + max_row: max_row, + max_col: max_col, + }; + }; + this.calc = function() { + var results = this.parse(); + var sheet_name = results.sheet_name; + var sheet = results.sheet; + var min_row = results.min_row; + var min_col = results.min_col; + var max_row = results.max_row; + var max_col = results.max_col; var matrix = []; for (var i = min_row; i <= max_row; i++) { var row = []; diff --git a/src/formulas-raw.js b/src/formulas-raw.js index 7469372..3746d39 100644 --- a/src/formulas-raw.js +++ b/src/formulas-raw.js @@ -29,6 +29,48 @@ function raw_offset(cell_ref, rows, columns, height, width) { } } +function row(cell_ref) { + if (cell_ref.args.length === 0) { + var row = +cell_ref.formula.name.replace(/^[A-Z]+/g, ''); + return row; + } else if (cell_ref.args.length === 1 && cell_ref.args[0].name === 'RefValue') { + var ref_value = cell_ref.args[0]; + var parsed_ref = ref_value.parseRef(); + var row = +parsed_ref.cell_name.replace(/^[A-Z]+/g, ''); + return row; + } else if (cell_ref.args.length === 1 && cell_ref.args[0] instanceof Range) { + var results = cell_ref.args[0].parse(); + var min_row = results.min_row; + var max_row = results.max_row; + var rows = []; + for (var i = min_row; i <= max_row; i++) { + rows.push(i); + } + return rows; + } +} + +function column(cell_ref) { + if (cell_ref.args.length === 0) { + var col = col_str_2_int(cell_ref.formula.name); + return col + 1; + } else if (cell_ref.args.length === 1 && cell_ref.args[0].name === 'RefValue') { + var ref_value = cell_ref.args[0]; + var parsed_ref = ref_value.parseRef(); + var col = col_str_2_int(parsed_ref.cell_name); + return col + 1; + } else if (cell_ref.args.length === 1 && cell_ref.args[0] instanceof Range) { + var results = cell_ref.args[0].parse(); + var min_col = results.min_col; + var max_col = results.max_col; + var cols = []; + for (var i = min_col; i <= max_col; i++) { + cols.push(i + 1); + } + return cols; + } +} + function iferror(cell_ref, onerrorvalue) { try { var value = cell_ref.calc(); @@ -102,6 +144,8 @@ function transpose(expressionWithRange) { module.exports = { 'OFFSET': raw_offset, + 'ROW': row, + 'COLUMN': column, 'IFERROR': iferror, 'IF': _if, 'AND': and, diff --git a/test/1-basic-test.js b/test/1-basic-test.js index f654307..bf57931 100644 --- a/test/1-basic-test.js +++ b/test/1-basic-test.js @@ -1205,6 +1205,42 @@ describe('XLSX_CALC', function() { }); }); + describe('ROW', function () { + it('returns row in which the formula appears', function () { + workbook.Sheets.Sheet1.A1.f = 'ROW()'; + XLSX_CALC(workbook); + assert.equal(workbook.Sheets.Sheet1.A1.v, 1); + }); + it('returns row of the reference', function () { + workbook.Sheets.Sheet1.A1.f = 'ROW(A2)'; + XLSX_CALC(workbook); + assert.equal(workbook.Sheets.Sheet1.A1.v, 2); + }); + it('returns row as an array if the reference is an array', function () { + workbook.Sheets.Sheet1.A1.f = 'ROW(A1:A3)'; + XLSX_CALC(workbook); + assert.deepEqual(workbook.Sheets.Sheet1.A1.v, [1, 2, 3]); + }); + }); + + describe('COLUMN', function () { + it('returns column in which the formula appears', function () { + workbook.Sheets.Sheet1.A1.f = 'COLUMN()'; + XLSX_CALC(workbook); + assert.equal(workbook.Sheets.Sheet1.A1.v, 1); + }); + it('returns column of the reference', function () { + workbook.Sheets.Sheet1.A1.f = 'COLUMN(B1)'; + XLSX_CALC(workbook); + assert.equal(workbook.Sheets.Sheet1.A1.v, 2); + }); + it('returns column as an array if the reference is an array', function () { + workbook.Sheets.Sheet1.A1.f = 'COLUMN(A1:C1)'; + XLSX_CALC(workbook); + assert.deepEqual(workbook.Sheets.Sheet1.A1.v, [1, 2, 3]); + }); + }); + describe('ISERROR', function () { it('returns true if in error', function () { workbook.Sheets.Sheet1.A1 = { f: "0/0" };