Skip to content

Commit 7b4da39

Browse files
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
1 parent bb603b3 commit 7b4da39

File tree

3 files changed

+70
-32
lines changed

3 files changed

+70
-32
lines changed

adjust.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ func adjustFormulaColumnName(name, operand string, abs, keepRelative bool, dir a
320320
return "", operand, false, err
321321
}
322322
if dir == columns && col >= num {
323-
col += offset
323+
if col += offset; col < 1 {
324+
col = 1
325+
}
324326
colName, err := ColumnNumberToName(col)
325327
return "", operand + colName, false, err
326328
}
@@ -334,8 +336,10 @@ func adjustFormulaRowNumber(name, operand string, abs, keepRelative bool, dir ad
334336
}
335337
row, _ := strconv.Atoi(name)
336338
if dir == rows && row >= num {
337-
row += offset
338-
if row <= 0 || row > TotalRows {
339+
if row += offset; row < 1 {
340+
row = 1
341+
}
342+
if row > TotalRows {
339343
return "", operand + name, false, ErrMaxRows
340344
}
341345
return "", operand + strconv.Itoa(row), false, nil

calc.go

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11602,7 +11602,22 @@ func (fn *formulaFuncs) ISNUMBER(argsList *list.List) formulaArg {
1160211602
if argsList.Len() != 1 {
1160311603
return newErrorFormulaArg(formulaErrorVALUE, "ISNUMBER requires 1 argument")
1160411604
}
11605-
if argsList.Front().Value.(formulaArg).Type == ArgNumber {
11605+
arg := argsList.Front().Value.(formulaArg)
11606+
if arg.Type == ArgMatrix {
11607+
var mtx [][]formulaArg
11608+
for _, row := range arg.Matrix {
11609+
var array []formulaArg
11610+
for _, val := range row {
11611+
if val.Type == ArgNumber {
11612+
array = append(array, newBoolFormulaArg(true))
11613+
}
11614+
array = append(array, newBoolFormulaArg(false))
11615+
}
11616+
mtx = append(mtx, array)
11617+
}
11618+
return newMatrixFormulaArg(mtx)
11619+
}
11620+
if arg.Type == ArgNumber {
1160611621
return newBoolFormulaArg(true)
1160711622
}
1160811623
return newBoolFormulaArg(false)
@@ -11951,11 +11966,14 @@ func (fn *formulaFuncs) OR(argsList *list.List) formulaArg {
1195111966
return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
1195211967
}
1195311968
case ArgMatrix:
11954-
// TODO
11955-
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
11969+
args := list.New()
11970+
for _, arg := range token.ToList() {
11971+
args.PushBack(arg)
11972+
}
11973+
return fn.OR(args)
1195611974
}
1195711975
}
11958-
return newStringFormulaArg(strings.ToUpper(strconv.FormatBool(or)))
11976+
return newBoolFormulaArg(or)
1195911977
}
1196011978

1196111979
// 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 {
1374113759
if args.Type != ArgList {
1374213760
return args
1374313761
}
13744-
findText := argsList.Front().Value.(formulaArg).Value()
13762+
findTextArg := argsList.Front().Value.(formulaArg)
1374513763
withinText := argsList.Front().Next().Value.(formulaArg).Value()
1374613764
startNum := int(args.List[0].Number)
13747-
if findText == "" {
13748-
return newNumberFormulaArg(float64(startNum))
13749-
}
1375013765
dbcs, search := name == "FINDB" || name == "SEARCHB", name == "SEARCH" || name == "SEARCHB"
13751-
if search {
13752-
findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText)
13753-
}
13754-
offset, ok := matchPattern(findText, withinText, dbcs, startNum)
13755-
if !ok {
13756-
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
13757-
}
13758-
result := offset
13759-
if dbcs {
13760-
var pre int
13761-
for idx := range withinText {
13762-
if pre > offset {
13763-
break
13766+
find := func(findText string) formulaArg {
13767+
if findText == "" {
13768+
return newNumberFormulaArg(float64(startNum))
13769+
}
13770+
if search {
13771+
findText, withinText = strings.ToUpper(findText), strings.ToUpper(withinText)
13772+
}
13773+
offset, ok := matchPattern(findText, withinText, dbcs, startNum)
13774+
if !ok {
13775+
return newErrorFormulaArg(formulaErrorVALUE, formulaErrorVALUE)
13776+
}
13777+
result := offset
13778+
if dbcs {
13779+
var pre int
13780+
for idx := range withinText {
13781+
if pre > offset {
13782+
break
13783+
}
13784+
if idx-pre > 1 {
13785+
result++
13786+
}
13787+
pre = idx
1376413788
}
13765-
if idx-pre > 1 {
13766-
result++
13789+
}
13790+
return newNumberFormulaArg(float64(result))
13791+
}
13792+
if findTextArg.Type == ArgMatrix {
13793+
var mtx [][]formulaArg
13794+
for _, row := range findTextArg.Matrix {
13795+
var array []formulaArg
13796+
for _, findText := range row {
13797+
array = append(array, find(findText.Value()))
1376713798
}
13768-
pre = idx
13799+
mtx = append(mtx, array)
1376913800
}
13801+
return newMatrixFormulaArg(mtx)
1377013802
}
13771-
return newNumberFormulaArg(float64(result))
13803+
return find(findTextArg.Value())
1377213804
}
1377313805

1377413806
// LEFT function returns a specified number of characters from the start of a

calc_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,8 +1451,9 @@ func TestCalcCellValue(t *testing.T) {
14511451
"=ISNONTEXT(\"Excelize\")": "FALSE",
14521452
"=ISNONTEXT(NA())": "TRUE",
14531453
// ISNUMBER
1454-
"=ISNUMBER(A1)": "TRUE",
1455-
"=ISNUMBER(D1)": "FALSE",
1454+
"=ISNUMBER(A1)": "TRUE",
1455+
"=ISNUMBER(D1)": "FALSE",
1456+
"=ISNUMBER(A1:B1)": "TRUE",
14561457
// ISODD
14571458
"=ISODD(A1)": "TRUE",
14581459
"=ISODD(A2)": "FALSE",
@@ -1526,6 +1527,7 @@ func TestCalcCellValue(t *testing.T) {
15261527
"=OR(1=2,2=3)": "FALSE",
15271528
"=OR(1=1,2=3)": "TRUE",
15281529
"=OR(\"TRUE\",\"FALSE\")": "TRUE",
1530+
"=OR(A1:B1)": "TRUE",
15291531
// SWITCH
15301532
"=SWITCH(1,1,\"A\",2,\"B\",3,\"C\",\"N\")": "A",
15311533
"=SWITCH(3,1,\"A\",2,\"B\",3,\"C\",\"N\")": "C",
@@ -1748,6 +1750,7 @@ func TestCalcCellValue(t *testing.T) {
17481750
"=FIND(\"\",\"Original Text\")": "1",
17491751
"=FIND(\"\",\"Original Text\",2)": "2",
17501752
"=FIND(\"s\",\"Sales\",2)": "5",
1753+
"=FIND(D1:E2,\"Month\")": "1",
17511754
// FINDB
17521755
"=FINDB(\"T\",\"Original Text\")": "10",
17531756
"=FINDB(\"t\",\"Original Text\")": "13",
@@ -3663,7 +3666,6 @@ func TestCalcCellValue(t *testing.T) {
36633666
"=NOT(\"\")": {"#VALUE!", "NOT expects 1 boolean or numeric argument"},
36643667
// OR
36653668
"=OR(\"text\")": {"#VALUE!", "#VALUE!"},
3666-
"=OR(A1:B1)": {"#VALUE!", "#VALUE!"},
36673669
"=OR(\"1\",\"TRUE\",\"FALSE\")": {"#VALUE!", "#VALUE!"},
36683670
"=OR()": {"#VALUE!", "OR requires at least 1 argument"},
36693671
"=OR(1" + strings.Repeat(",1", 30) + ")": {"#VALUE!", "OR accepts at most 30 arguments"},
@@ -4773,7 +4775,7 @@ func TestCalcOR(t *testing.T) {
47734775
})
47744776
fn := formulaFuncs{}
47754777
result := fn.OR(argsList)
4776-
assert.Equal(t, result.String, "FALSE")
4778+
assert.Equal(t, result.Value(), "FALSE")
47774779
assert.Empty(t, result.Error)
47784780
}
47794781

0 commit comments

Comments
 (0)