diff --git a/adjust.go b/adjust.go index 5d6004067c9159a258075f242f1a6c1d6300fb57..75faf16ad6a6a3b2a86bf297e2d4d4a9812150f0 100644 --- a/adjust.go +++ b/adjust.go @@ -320,7 +320,9 @@ func adjustFormulaColumnName(name, operand string, abs, keepRelative bool, dir a return "", operand, false, err } if dir == columns && col >= num { - col += offset + if col += offset; col < 1 { + col = 1 + } colName, err := ColumnNumberToName(col) return "", operand + colName, false, err } @@ -334,8 +336,10 @@ func adjustFormulaRowNumber(name, operand string, abs, keepRelative bool, dir ad } row, _ := strconv.Atoi(name) if dir == rows && row >= num { - row += offset - if row <= 0 || row > TotalRows { + if row += offset; row < 1 { + row = 1 + } + if row > TotalRows { return "", operand + name, false, ErrMaxRows } return "", operand + strconv.Itoa(row), false, nil diff --git a/calc.go b/calc.go index 496ecd41eec32b6bd4986cab6d2322cd21b12119..be5f6416aa063f25f0ae6db641c7070b00083e6c 100644 --- a/calc.go +++ b/calc.go @@ -11602,7 +11602,22 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg { if argsList.Len() != 1 { return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument") } - if argsList.Front().Value.(formulaArg).Type == ArgNumber { + arg := argsList.Front().Value.(formulaArg) + if arg.Type == ArgMatrix { + var mtx [][]formulaArg + for _, row := range arg.Matrix { + var array []formulaArg + for _, val := range row { + if val.Type == ArgNumber { + array = append(array, newBoolFormulaArg(true)) + } + array = append(array, newBoolFormulaArg(false)) + } + mtx = append(mtx, array) + } + return newMatrixFormulaArg(mtx) + } + if arg.Type == ArgNumber { return newBoolFormulaArg(true) } return newBoolFormulaArg(false) @@ -11951,11 +11966,14 @@ func (fn *formulaFuncs) OR(argsList *list.List) formulaArg { return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or))) } case ArgMatrix: - // TODO - return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) + args := list.New() + for _, arg := range token.ToList() { + args.PushBack(arg) + } + return fn.OR(args) } } - return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or))) + return newBoolFormulaArg(or) } // SWITCH function compares a number of supplied values to a supplied test @@ -13741,34 +13759,48 @@ func (fn *formulaFuncs) find(name string, argsList *list.List) formulaArg { if args.Type != ArgList { return args } - findText := argsList.Front().Value.(formulaArg).Value() + findTextArg := argsList.Front().Value.(formulaArg) withinText := argsList.Front().Next().Value.(formulaArg).Value() startNum := int(args.List[0].Number) - if findText == "" { - return newNumberFormulaArg(float64(startNum)) - } dbcs, search := name == "FINDB" || name == "SEARCHB", name == "SEARCH" || name == "SEARCHB" - if search { - findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText) - } - offset, ok := matchPattern(findText, withinText, dbcs, startNum) - if !ok { - return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) - } - result := offset - if dbcs { - var pre int - for idx := range withinText { - if pre > offset { - break + find := func(findText string) formulaArg { + if findText == "" { + return newNumberFormulaArg(float64(startNum)) + } + if search { + findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText) + } + offset, ok := matchPattern(findText, withinText, dbcs, startNum) + if !ok { + return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) + } + result := offset + if dbcs { + var pre int + for idx := range withinText { + if pre > offset { + break + } + if idx-pre > 1 { + result++ + } + pre = idx } - if idx-pre > 1 { - result++ + } + return newNumberFormulaArg(float64(result)) + } + if findTextArg.Type == ArgMatrix { + var mtx [][]formulaArg + for _, row := range findTextArg.Matrix { + var array []formulaArg + for _, findText := range row { + array = append(array, find(findText.Value())) } - pre = idx + mtx = append(mtx, array) } + return newMatrixFormulaArg(mtx) } - return newNumberFormulaArg(float64(result)) + return find(findTextArg.Value()) } // LEFT function returns a specified number of characters from the start of a diff --git a/calc_test.go b/calc_test.go index 350e51651108adceceb2f53d7a92b61bf0047f93..123db378bdf290ad2c9f4a7fafb329fdee92f83f 100644 --- a/calc_test.go +++ b/calc_test.go @@ -1451,8 +1451,9 @@ func TestCalcCellValue(t *testing.T) { "=ISNONTEXT(\"Excelize\")": "FALSE", "=ISNONTEXT(NA())": "TRUE", // ISNUMBER - "=ISNUMBER(A1)": "TRUE", - "=ISNUMBER(D1)": "FALSE", + "=ISNUMBER(A1)": "TRUE", + "=ISNUMBER(D1)": "FALSE", + "=ISNUMBER(A1:B1)": "TRUE", // ISODD "=ISODD(A1)": "TRUE", "=ISODD(A2)": "FALSE", @@ -1526,6 +1527,7 @@ func TestCalcCellValue(t *testing.T) { "=OR(1=2,2=3)": "FALSE", "=OR(1=1,2=3)": "TRUE", "=OR(\"TRUE\",\"FALSE\")": "TRUE", + "=OR(A1:B1)": "TRUE", // SWITCH "=SWITCH(1,1,\"A\",2,\"B\",3,\"C\",\"N\")": "A", "=SWITCH(3,1,\"A\",2,\"B\",3,\"C\",\"N\")": "C", @@ -1748,6 +1750,7 @@ func TestCalcCellValue(t *testing.T) { "=FIND(\"\",\"Original Text\")": "1", "=FIND(\"\",\"Original Text\",2)": "2", "=FIND(\"s\",\"Sales\",2)": "5", + "=FIND(D1:E2,\"Month\")": "1", // FINDB "=FINDB(\"T\",\"Original Text\")": "10", "=FINDB(\"t\",\"Original Text\")": "13", @@ -3663,7 +3666,6 @@ func TestCalcCellValue(t *testing.T) { "=NOT(\"\")": {"#VALUE!", "NOT expects 1 boolean or numeric argument"}, // OR "=OR(\"text\")": {"#VALUE!", "#VALUE!"}, - "=OR(A1:B1)": {"#VALUE!", "#VALUE!"}, "=OR(\"1\",\"TRUE\",\"FALSE\")": {"#VALUE!", "#VALUE!"}, "=OR()": {"#VALUE!", "OR requires at least 1 argument"}, "=OR(1" + strings.Repeat(",1", 30) + ")": {"#VALUE!", "OR accepts at most 30 arguments"}, @@ -4773,7 +4775,7 @@ func TestCalcOR(t *testing.T) { }) fn := formulaFuncs{} result := fn.OR(argsList) - assert.Equal(t, result.String, "FALSE") + assert.Equal(t, result.Value(), "FALSE") assert.Empty(t, result.Error) }