Skip to content

Commit

Permalink
fix shared formula incorrect (qax-os#844)
Browse files Browse the repository at this point in the history
  • Loading branch information
raochq committed May 19, 2021
1 parent 5bf3ea6 commit 6c789cb
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 4 deletions.
101 changes: 98 additions & 3 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion excelize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestOpenFile(t *testing.T) {
assert.NoError(t, err)
_, err = f.GetCellFormula("Sheet2", "I11")
assert.NoError(t, err)
getSharedForumula(&xlsxWorksheet{}, "")
getSharedForumula(&xlsxWorksheet{}, "", "")

// Test read cell value with given illegal rows number.
_, err = f.GetCellValue("Sheet2", "a-1")
Expand Down

0 comments on commit 6c789cb

Please sign in to comment.