未验证 提交 7b4da390 编写于 作者: 岳晨旭 提交者: GitHub

This closes #1819, closes #1827, formula function ISNUMBER, OR and FIND...

This closes #1819, closes #1827, formula function ISNUMBER, OR and FIND support matrix arguments (#1829)

- Keep minimum column and row number in formula operand when deleting columns and rows
- Update unit tests
上级 bb603b37
...@@ -320,7 +320,9 @@ func adjustFormulaColumnName(name, operand string, abs, keepRelative bool, dir a ...@@ -320,7 +320,9 @@ func adjustFormulaColumnName(name, operand string, abs, keepRelative bool, dir a
return "", operand, false, err return "", operand, false, err
} }
if dir == columns && col >= num { if dir == columns && col >= num {
col += offset if col += offset; col < 1 {
col = 1
}
colName, err := ColumnNumberToName(col) colName, err := ColumnNumberToName(col)
return "", operand + colName, false, err return "", operand + colName, false, err
} }
...@@ -334,8 +336,10 @@ func adjustFormulaRowNumber(name, operand string, abs, keepRelative bool, dir ad ...@@ -334,8 +336,10 @@ func adjustFormulaRowNumber(name, operand string, abs, keepRelative bool, dir ad
} }
row, _ := strconv.Atoi(name) row, _ := strconv.Atoi(name)
if dir == rows && row >= num { if dir == rows && row >= num {
row += offset if row += offset; row < 1 {
if row <= 0 || row > TotalRows { row = 1
}
if row > TotalRows {
return "", operand + name, false, ErrMaxRows return "", operand + name, false, ErrMaxRows
} }
return "", operand + strconv.Itoa(row), false, nil return "", operand + strconv.Itoa(row), false, nil
......
...@@ -11602,7 +11602,22 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg { ...@@ -11602,7 +11602,22 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg {
if argsList.Len() != 1 { if argsList.Len() != 1 {
return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument") 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(true)
} }
return newBoolFormulaArg(false) return newBoolFormulaArg(false)
...@@ -11951,11 +11966,14 @@ func (fn *formulaFuncs) OR(argsList *list.List) formulaArg { ...@@ -11951,11 +11966,14 @@ func (fn *formulaFuncs) OR(argsList *list.List) formulaArg {
return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or))) return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
} }
case ArgMatrix: case ArgMatrix:
// TODO args := list.New()
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) 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 // 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 { ...@@ -13741,34 +13759,48 @@ func (fn *formulaFuncs) find(name string, argsList *list.List) formulaArg {
if args.Type != ArgList { if args.Type != ArgList {
return args return args
} }
findText := argsList.Front().Value.(formulaArg).Value() findTextArg := argsList.Front().Value.(formulaArg)
withinText := argsList.Front().Next().Value.(formulaArg).Value() withinText := argsList.Front().Next().Value.(formulaArg).Value()
startNum := int(args.List[0].Number) startNum := int(args.List[0].Number)
if findText == "" {
return newNumberFormulaArg(float64(startNum))
}
dbcs, search := name == "FINDB" || name == "SEARCHB", name == "SEARCH" || name == "SEARCHB" dbcs, search := name == "FINDB" || name == "SEARCHB", name == "SEARCH" || name == "SEARCHB"
if search { find := func(findText string) formulaArg {
findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText) if findText == "" {
} return newNumberFormulaArg(float64(startNum))
offset, ok := matchPattern(findText, withinText, dbcs, startNum) }
if !ok { if search {
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE) findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText)
} }
result := offset offset, ok := matchPattern(findText, withinText, dbcs, startNum)
if dbcs { if !ok {
var pre int return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
for idx := range withinText { }
if pre > offset { result := offset
break 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 // LEFT function returns a specified number of characters from the start of a
......
...@@ -1451,8 +1451,9 @@ func TestCalcCellValue(t *testing.T) { ...@@ -1451,8 +1451,9 @@ func TestCalcCellValue(t *testing.T) {
"=ISNONTEXT(\"Excelize\")": "FALSE", "=ISNONTEXT(\"Excelize\")": "FALSE",
"=ISNONTEXT(NA())": "TRUE", "=ISNONTEXT(NA())": "TRUE",
// ISNUMBER // ISNUMBER
"=ISNUMBER(A1)": "TRUE", "=ISNUMBER(A1)": "TRUE",
"=ISNUMBER(D1)": "FALSE", "=ISNUMBER(D1)": "FALSE",
"=ISNUMBER(A1:B1)": "TRUE",
// ISODD // ISODD
"=ISODD(A1)": "TRUE", "=ISODD(A1)": "TRUE",
"=ISODD(A2)": "FALSE", "=ISODD(A2)": "FALSE",
...@@ -1526,6 +1527,7 @@ func TestCalcCellValue(t *testing.T) { ...@@ -1526,6 +1527,7 @@ func TestCalcCellValue(t *testing.T) {
"=OR(1=2,2=3)": "FALSE", "=OR(1=2,2=3)": "FALSE",
"=OR(1=1,2=3)": "TRUE", "=OR(1=1,2=3)": "TRUE",
"=OR(\"TRUE\",\"FALSE\")": "TRUE", "=OR(\"TRUE\",\"FALSE\")": "TRUE",
"=OR(A1:B1)": "TRUE",
// SWITCH // SWITCH
"=SWITCH(1,1,\"A\",2,\"B\",3,\"C\",\"N\")": "A", "=SWITCH(1,1,\"A\",2,\"B\",3,\"C\",\"N\")": "A",
"=SWITCH(3,1,\"A\",2,\"B\",3,\"C\",\"N\")": "C", "=SWITCH(3,1,\"A\",2,\"B\",3,\"C\",\"N\")": "C",
...@@ -1748,6 +1750,7 @@ func TestCalcCellValue(t *testing.T) { ...@@ -1748,6 +1750,7 @@ func TestCalcCellValue(t *testing.T) {
"=FIND(\"\",\"Original Text\")": "1", "=FIND(\"\",\"Original Text\")": "1",
"=FIND(\"\",\"Original Text\",2)": "2", "=FIND(\"\",\"Original Text\",2)": "2",
"=FIND(\"s\",\"Sales\",2)": "5", "=FIND(\"s\",\"Sales\",2)": "5",
"=FIND(D1:E2,\"Month\")": "1",
// FINDB // FINDB
"=FINDB(\"T\",\"Original Text\")": "10", "=FINDB(\"T\",\"Original Text\")": "10",
"=FINDB(\"t\",\"Original Text\")": "13", "=FINDB(\"t\",\"Original Text\")": "13",
...@@ -3663,7 +3666,6 @@ func TestCalcCellValue(t *testing.T) { ...@@ -3663,7 +3666,6 @@ func TestCalcCellValue(t *testing.T) {
"=NOT(\"\")": {"#VALUE!", "NOT expects 1 boolean or numeric argument"}, "=NOT(\"\")": {"#VALUE!", "NOT expects 1 boolean or numeric argument"},
// OR // OR
"=OR(\"text\")": {"#VALUE!", "#VALUE!"}, "=OR(\"text\")": {"#VALUE!", "#VALUE!"},
"=OR(A1:B1)": {"#VALUE!", "#VALUE!"},
"=OR(\"1\",\"TRUE\",\"FALSE\")": {"#VALUE!", "#VALUE!"}, "=OR(\"1\",\"TRUE\",\"FALSE\")": {"#VALUE!", "#VALUE!"},
"=OR()": {"#VALUE!", "OR requires at least 1 argument"}, "=OR()": {"#VALUE!", "OR requires at least 1 argument"},
"=OR(1" + strings.Repeat(",1", 30) + ")": {"#VALUE!", "OR accepts at most 30 arguments"}, "=OR(1" + strings.Repeat(",1", 30) + ")": {"#VALUE!", "OR accepts at most 30 arguments"},
...@@ -4773,7 +4775,7 @@ func TestCalcOR(t *testing.T) { ...@@ -4773,7 +4775,7 @@ func TestCalcOR(t *testing.T) {
}) })
fn := formulaFuncs{} fn := formulaFuncs{}
result := fn.OR(argsList) result := fn.OR(argsList)
assert.Equal(t, result.String, "FALSE") assert.Equal(t, result.Value(), "FALSE")
assert.Empty(t, result.Error) assert.Empty(t, result.Error)
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册