forked from p30928647/excelize
This commit is contained in:
parent
363fa940ac
commit
ad90cea78b
44
calc.go
44
calc.go
|
@ -197,8 +197,10 @@ var (
|
||||||
// calcContext defines the formula execution context.
|
// calcContext defines the formula execution context.
|
||||||
type calcContext struct {
|
type calcContext struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
entry string
|
entry string
|
||||||
iterations map[string]uint
|
maxCalcIterations uint
|
||||||
|
iterations map[string]uint
|
||||||
|
iterationsCache map[string]formulaArg
|
||||||
}
|
}
|
||||||
|
|
||||||
// cellRef defines the structure of a cell reference.
|
// cellRef defines the structure of a cell reference.
|
||||||
|
@ -774,8 +776,10 @@ func (f *File) CalcCellValue(sheet, cell string, opts ...Options) (result string
|
||||||
token formulaArg
|
token formulaArg
|
||||||
)
|
)
|
||||||
if token, err = f.calcCellValue(&calcContext{
|
if token, err = f.calcCellValue(&calcContext{
|
||||||
entry: fmt.Sprintf("%s!%s", sheet, cell),
|
entry: fmt.Sprintf("%s!%s", sheet, cell),
|
||||||
iterations: make(map[string]uint),
|
maxCalcIterations: getOptions(opts...).MaxCalcIterations,
|
||||||
|
iterations: make(map[string]uint),
|
||||||
|
iterationsCache: make(map[string]formulaArg),
|
||||||
}, sheet, cell); err != nil {
|
}, sheet, cell); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1527,17 +1531,6 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
|
||||||
value string
|
value string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
ref := fmt.Sprintf("%s!%s", sheet, cell)
|
|
||||||
if formula, _ := f.GetCellFormula(sheet, cell); len(formula) != 0 {
|
|
||||||
ctx.Lock()
|
|
||||||
if ctx.entry != ref && ctx.iterations[ref] <= f.options.MaxCalcIterations {
|
|
||||||
ctx.iterations[ref]++
|
|
||||||
ctx.Unlock()
|
|
||||||
arg, _ = f.calcCellValue(ctx, sheet, cell)
|
|
||||||
return arg, nil
|
|
||||||
}
|
|
||||||
ctx.Unlock()
|
|
||||||
}
|
|
||||||
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
|
if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
|
||||||
return arg, err
|
return arg, err
|
||||||
}
|
}
|
||||||
|
@ -1551,8 +1544,25 @@ func (f *File) cellResolver(ctx *calcContext, sheet, cell string) (formulaArg, e
|
||||||
return newEmptyFormulaArg(), err
|
return newEmptyFormulaArg(), err
|
||||||
}
|
}
|
||||||
return arg.ToNumber(), err
|
return arg.ToNumber(), err
|
||||||
default:
|
case CellTypeInlineString, CellTypeSharedString:
|
||||||
return arg, err
|
return arg, err
|
||||||
|
case CellTypeFormula:
|
||||||
|
ref := fmt.Sprintf("%s!%s", sheet, cell)
|
||||||
|
if ctx.entry != ref {
|
||||||
|
ctx.Lock()
|
||||||
|
if ctx.iterations[ref] <= ctx.maxCalcIterations {
|
||||||
|
ctx.iterations[ref]++
|
||||||
|
ctx.Unlock()
|
||||||
|
arg, _ = f.calcCellValue(ctx, sheet, cell)
|
||||||
|
ctx.iterationsCache[ref] = arg
|
||||||
|
return arg, nil
|
||||||
|
}
|
||||||
|
ctx.Unlock()
|
||||||
|
return ctx.iterationsCache[ref], nil
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return newEmptyFormulaArg(), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7746,7 +7756,7 @@ func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg {
|
||||||
}
|
}
|
||||||
var count float64
|
var count float64
|
||||||
for _, cell := range argsList.Front().Value.(formulaArg).ToList() {
|
for _, cell := range argsList.Front().Value.(formulaArg).ToList() {
|
||||||
if cell.Value() == "" {
|
if cell.Type == ArgEmpty {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
calc_test.go
19
calc_test.go
|
@ -1023,7 +1023,7 @@ func TestCalcCellValue(t *testing.T) {
|
||||||
"=COUNTBLANK(MUNIT(1))": "0",
|
"=COUNTBLANK(MUNIT(1))": "0",
|
||||||
"=COUNTBLANK(1)": "0",
|
"=COUNTBLANK(1)": "0",
|
||||||
"=COUNTBLANK(B1:C1)": "1",
|
"=COUNTBLANK(B1:C1)": "1",
|
||||||
"=COUNTBLANK(C1)": "1",
|
"=COUNTBLANK(C1)": "0",
|
||||||
// COUNTIF
|
// COUNTIF
|
||||||
"=COUNTIF(D1:D9,\"Jan\")": "4",
|
"=COUNTIF(D1:D9,\"Jan\")": "4",
|
||||||
"=COUNTIF(D1:D9,\"<>Jan\")": "5",
|
"=COUNTIF(D1:D9,\"<>Jan\")": "5",
|
||||||
|
@ -5871,3 +5871,20 @@ func TestCalcColRowQRDecomposition(t *testing.T) {
|
||||||
assert.False(t, calcRowQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
|
assert.False(t, calcRowQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
|
||||||
assert.False(t, calcColQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
|
assert.False(t, calcColQRDecomposition([][]float64{{0, 0}, {0, 0}}, []float64{0, 0}, 1, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalcCellResolver(t *testing.T) {
|
||||||
|
f := NewFile()
|
||||||
|
// Test reference a cell multiple times in a formula
|
||||||
|
assert.NoError(t, f.SetCellValue("Sheet1", "A1", "VALUE1"))
|
||||||
|
assert.NoError(t, f.SetCellFormula("Sheet1", "A2", "=A1"))
|
||||||
|
for formula, expected := range map[string]string{
|
||||||
|
"=CONCATENATE(A1,\"_\",A1)": "VALUE1_VALUE1",
|
||||||
|
"=CONCATENATE(A1,\"_\",A2)": "VALUE1_VALUE1",
|
||||||
|
"=CONCATENATE(A2,\"_\",A2)": "VALUE1_VALUE1",
|
||||||
|
} {
|
||||||
|
assert.NoError(t, f.SetCellFormula("Sheet1", "A3", formula))
|
||||||
|
result, err := f.CalcCellValue("Sheet1", "A3")
|
||||||
|
assert.NoError(t, err, formula)
|
||||||
|
assert.Equal(t, expected, result, formula)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue