From 703b73779c06265bc8f23e3d9cbd628d6635fead Mon Sep 17 00:00:00 2001 From: xuri Date: Mon, 25 Mar 2024 08:33:29 +0800 Subject: [PATCH] This closes #1861, fix missing parentheses in the adjusted formula - Allow adjust cell reference with max rows/columns - Fix incorrect data validation escape result - Update out date reference link in the documentation - Update unit tests --- adjust.go | 57 +++++++++++++++++++++++++++----------------------- adjust_test.go | 12 +++++++++-- excelize.go | 6 +++--- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/adjust.go b/adjust.go index 46b8215..7c8ec9e 100644 --- a/adjust.go +++ b/adjust.go @@ -239,6 +239,17 @@ func (f *File) adjustSingleRowFormulas(sheet, sheetN string, r *xlsxRow, num, of // adjustCellRef provides a function to adjust cell reference. func (f *File) adjustCellRef(cellRef string, dir adjustDirection, num, offset int) (string, error) { var SQRef []string + applyOffset := func(coordinates []int, idx1, idx2, maxVal int) []int { + if coordinates[idx1] >= num { + coordinates[idx1] += offset + } + if coordinates[idx2] >= num { + if coordinates[idx2] += offset; coordinates[idx2] > maxVal { + coordinates[idx2] = maxVal + } + } + return coordinates + } for _, ref := range strings.Split(cellRef, " ") { if !strings.Contains(ref, ":") { ref += ":" + ref @@ -251,22 +262,12 @@ func (f *File) adjustCellRef(cellRef string, dir adjustDirection, num, offset in if offset < 0 && coordinates[0] == coordinates[2] { continue } - if coordinates[0] >= num { - coordinates[0] += offset - } - if coordinates[2] >= num { - coordinates[2] += offset - } + coordinates = applyOffset(coordinates, 0, 2, MaxColumns) } else { if offset < 0 && coordinates[1] == coordinates[3] { continue } - if coordinates[1] >= num { - coordinates[1] += offset - } - if coordinates[3] >= num { - coordinates[3] += offset - } + coordinates = applyOffset(coordinates, 1, 3, TotalRows) } if ref, err = coordinatesToRangeRef(coordinates); err != nil { return "", err @@ -446,12 +447,8 @@ func (f *File) adjustFormulaRef(sheet, sheetN, formula string, keepRelative bool val += operand continue } - if isFunctionStartToken(token) { - val += token.TValue + string(efp.ParenOpen) - continue - } - if isFunctionStopToken(token) { - val += token.TValue + string(efp.ParenClose) + if paren := transformParenthesesToken(token); paren != "" { + val += transformParenthesesToken(token) continue } if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText { @@ -463,6 +460,18 @@ func (f *File) adjustFormulaRef(sheet, sheetN, formula string, keepRelative bool return val, nil } +// transformParenthesesToken returns formula part with parentheses by given +// token. +func transformParenthesesToken(token efp.Token) string { + if isFunctionStartToken(token) || isBeginParenthesesToken(token) { + return token.TValue + string(efp.ParenOpen) + } + if isFunctionStopToken(token) || isEndParenthesesToken(token) { + return token.TValue + string(efp.ParenClose) + } + return "" +} + // adjustRangeSheetName returns replaced range reference by given source and // target sheet name. func adjustRangeSheetName(rng, source, target string) string { @@ -551,12 +560,8 @@ func transformArrayFormula(tokens []efp.Token, afs []arrayFormulaOperandToken) s if skip { continue } - if isFunctionStartToken(token) { - val += token.TValue + string(efp.ParenOpen) - continue - } - if isFunctionStopToken(token) { - val += token.TValue + string(efp.ParenClose) + if paren := transformParenthesesToken(token); paren != "" { + val += transformParenthesesToken(token) continue } if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeText { @@ -985,14 +990,14 @@ func (f *File) adjustDataValidations(ws *xlsxWorksheet, sheet string, dir adjust worksheet.DataValidations.DataValidation[i].Sqref = ref } if worksheet.DataValidations.DataValidation[i].Formula1 != nil { - formula := unescapeDataValidationFormula(worksheet.DataValidations.DataValidation[i].Formula1.Content) + formula := formulaUnescaper.Replace(worksheet.DataValidations.DataValidation[i].Formula1.Content) if formula, err = f.adjustFormulaRef(sheet, sheetN, formula, false, dir, num, offset); err != nil { return err } worksheet.DataValidations.DataValidation[i].Formula1 = &xlsxInnerXML{Content: formulaEscaper.Replace(formula)} } if worksheet.DataValidations.DataValidation[i].Formula2 != nil { - formula := unescapeDataValidationFormula(worksheet.DataValidations.DataValidation[i].Formula2.Content) + formula := formulaUnescaper.Replace(worksheet.DataValidations.DataValidation[i].Formula2.Content) if formula, err = f.adjustFormulaRef(sheet, sheetN, formula, false, dir, num, offset); err != nil { return err } diff --git a/adjust_test.go b/adjust_test.go index 00b5112..2982562 100644 --- a/adjust_test.go +++ b/adjust_test.go @@ -463,6 +463,14 @@ func TestAdjustCols(t *testing.T) { assert.NoError(t, f.InsertCols("Sheet1", "A", 2)) assert.Nil(t, ws.(*xlsxWorksheet).Cols) + + f = NewFile() + assert.NoError(t, f.SetCellFormula("Sheet1", "A2", "(1-0.5)/2")) + assert.NoError(t, f.InsertCols("Sheet1", "A", 1)) + formula, err := f.GetCellFormula("Sheet1", "B2") + assert.NoError(t, err) + assert.Equal(t, "(1-0.5)/2", formula) + assert.NoError(t, f.Close()) } func TestAdjustColDimensions(t *testing.T) { @@ -1061,13 +1069,13 @@ func TestAdjustDataValidations(t *testing.T) { // Test adjust data validation with multiple cell range dv = NewDataValidation(true) - dv.Sqref = "G1:G3 H1:H3" + dv.Sqref = "G1:G3 H1:H3 A3:A1048576" assert.NoError(t, dv.SetDropList([]string{"1", "2", "3"})) assert.NoError(t, f.AddDataValidation("Sheet1", dv)) assert.NoError(t, f.InsertRows("Sheet1", 2, 1)) dvs, err = f.GetDataValidations("Sheet1") assert.NoError(t, err) - assert.Equal(t, "G1:G4 H1:H4", dvs[3].Sqref) + assert.Equal(t, "G1:G4 H1:H4 A4:A1048576", dvs[3].Sqref) dv = NewDataValidation(true) dv.Sqref = "C5:D6" diff --git a/excelize.go b/excelize.go index de385de..2641018 100644 --- a/excelize.go +++ b/excelize.go @@ -453,14 +453,14 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int { // UpdateLinkedValue fix linked values within a spreadsheet are not updating in // Office Excel application. This function will be remove value tag when met a // cell have a linked value. Reference -// https://social.technet.microsoft.com/Forums/office/en-US/e16bae1f-6a2c-4325-8013-e989a3479066/excel-2010-linked-cells-not-updating +// https://learn.microsoft.com/en-us/archive/msdn-technet-forums/e16bae1f-6a2c-4325-8013-e989a3479066 // // Notice: after opening generated workbook, Excel will update the linked value // and generate a new value and will prompt to save the file or not. // // For example: // -// +// // // SUM(Sheet2!D2,Sheet2!D11) // 100 @@ -469,7 +469,7 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int { // // to // -// +// // // SUM(Sheet2!D2,Sheet2!D11) //