diff --git a/cell.go b/cell.go index f94b81e9d52..8d183b2cc04 100644 --- a/cell.go +++ b/cell.go @@ -348,7 +348,7 @@ func (f *File) GetCellFormula(sheet, axis string) (string, error) { return "", false, nil } if c.F.T == STCellFormulaTypeShared { - return getSharedForumula(x, c.F.Si), true, nil + return getSharedForumula(x, c.F.Si, c.R), true, nil } return c.F.Content, true, nil }) @@ -942,13 +942,108 @@ func isOverlap(rect1, rect2 []int) bool { // // Note that this function not validate ref tag to check the cell if or not in // allow area, and always return origin shared formula. -func getSharedForumula(ws *xlsxWorksheet, si string) string { +func getSharedForumula(ws *xlsxWorksheet, si string, axis string) string { for _, r := range ws.SheetData.Row { for _, c := range r.C { if c.F != nil && c.F.Ref != "" && c.F.T == STCellFormulaTypeShared && c.F.Si == si { - return c.F.Content + var res string + col, row, _ := CellNameToCoordinates(axis) + sharedCol, sharedRow, _ := CellNameToCoordinates(c.R) + dCol := col - sharedCol + dRow := row - sharedRow + orig := []byte(c.F.Content) + var start, end int + var stringLiteral bool + for end = 0; end < len(orig); end++ { + c := orig[end] + if c == '"' { + stringLiteral = !stringLiteral + } + if stringLiteral { + continue // Skip characters in quotes + } + if c >= 'A' && c <= 'Z' || c == '$' { + res += string(orig[start:end]) + start = end + end++ + foundNum := false + for ; end < len(orig); end++ { + idc := orig[end] + if idc >= '0' && idc <= '9' || idc == '$' { + foundNum = true + } else if idc >= 'A' && idc <= 'Z' { + if foundNum { + break + } + } else { + break + } + } + if foundNum { + cellID := string(orig[start:end]) + res += shiftCell(cellID, dCol, dRow) + start = end + } + } + } + if start < len(orig) { + res += string(orig[start:]) + } + return res } } } return "" } + +// shiftCell returns the cell shifted according to dCol and dRow taking into consideration of absolute +// references with dollar sign ($) +func shiftCell(cellID string, dCol, dRow int) string { + fCol, fRow, _ := CellNameToCoordinates2(cellID) + signCol, signRow := "", "" + if strings.Index(cellID, "$") == 0 { + signCol = "$" + } else { + // Shift column + fCol += dCol + } + if strings.LastIndex(cellID, "$") > 0 { + signRow = "$" + } else { + // Shift row + fRow += dRow + } + colName, _ := ColumnNumberToName(fCol) + return signCol + colName + signRow + strconv.Itoa(fRow) +} + +// CellNameToCoordinates2 converts cell name to coordinates taking into consideration of absolute +// "B3" "$B$3" "B$3" "$B3" returns 2,3,nil +func CellNameToCoordinates2(cell string) (col, row int, err error) { + wrap := func(err error) (int, int, error) { + return -1, -1, fmt.Errorf("CellNameToCoordinates2(%q): %w", cell, err) + } + var colName = strings.Map(func(rune rune) rune { + switch { + case 'A' <= rune && rune <= 'Z': + return rune + case 'a' <= rune && rune <= 'z': + return rune - 32 + } + return -1 + }, cell) + row, err = strconv.Atoi(strings.Map(func(rune rune) rune { + if rune >= 48 && rune < 58 { + return rune + } + return -1 + }, cell)) + if err != nil { + return wrap(err) + } + col, err = ColumnNameToNumber(colName) + if err != nil { + return wrap(err) + } + return +}