Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xuri
excelize
提交
ec45d67e
excelize
项目概览
xuri
/
excelize
通知
13
Star
2
Fork
4
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
excelize
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
已验证
提交
ec45d67e
编写于
2月 13, 2021
作者:
xurime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
binary search in range lookup and new formula function: LOOKUP
上级
3648335d
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
315 addition
and
89 deletion
+315
-89
LICENSE
LICENSE
+1
-1
calc.go
calc.go
+179
-36
calc_test.go
calc_test.go
+135
-52
未找到文件。
LICENSE
浏览文件 @
ec45d67e
BSD 3-Clause License
Copyright (c) 2016-202
0
The excelize Authors.
Copyright (c) 2016-202
1
The excelize Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
...
...
calc.go
浏览文件 @
ec45d67e
...
...
@@ -223,6 +223,7 @@ var tokenPriority = map[string]int{
// FLOOR.MATH
// FLOOR.PRECISE
// GCD
// HLOOKUP
// IF
// INT
// ISBLANK
...
...
@@ -239,6 +240,7 @@ var tokenPriority = map[string]int{
// LN
// LOG
// LOG10
// LOOKUP
// LOWER
// MDETERM
// MEDIAN
...
...
@@ -275,6 +277,7 @@ var tokenPriority = map[string]int{
// TRIM
// TRUNC
// UPPER
// VLOOKUP
//
func
(
f
*
File
)
CalcCellValue
(
sheet
,
cell
string
)
(
result
string
,
err
error
)
{
var
(
...
...
@@ -2335,8 +2338,8 @@ func (fn *formulaFuncs) MUNIT(argsList *list.List) (result formulaArg) {
return
newErrorFormulaArg
(
formulaErrorVALUE
,
"MUNIT requires 1 numeric argument"
)
}
dimension
:=
argsList
.
Back
()
.
Value
.
(
formulaArg
)
.
ToNumber
()
if
dimension
.
Type
==
ArgError
{
return
dimension
if
dimension
.
Type
==
ArgError
||
dimension
.
Number
<
0
{
return
newErrorFormulaArg
(
formulaErrorVALUE
,
dimension
.
Error
)
}
matrix
:=
make
([][]
formulaArg
,
0
,
int
(
dimension
.
Number
))
for
i
:=
0
;
i
<
int
(
dimension
.
Number
);
i
++
{
...
...
@@ -3607,8 +3610,7 @@ func matchPattern(pattern, name string) (matched bool) {
if
pattern
==
"*"
{
return
true
}
rname
:=
make
([]
rune
,
0
,
len
(
name
))
rpattern
:=
make
([]
rune
,
0
,
len
(
pattern
))
rname
,
rpattern
:=
make
([]
rune
,
0
,
len
(
name
)),
make
([]
rune
,
0
,
len
(
pattern
))
for
_
,
r
:=
range
name
{
rname
=
append
(
rname
,
r
)
}
...
...
@@ -3636,11 +3638,9 @@ func compareFormulaArg(lhs, rhs formulaArg, caseSensitive, exactMatch bool) byte
}
return
criteriaG
case
ArgString
:
ls
:=
lhs
.
String
rs
:=
rhs
.
String
ls
,
rs
:=
lhs
.
String
,
rhs
.
String
if
!
caseSensitive
{
ls
=
strings
.
ToLower
(
ls
)
rs
=
strings
.
ToLower
(
rs
)
ls
,
rs
=
strings
.
ToLower
(
ls
),
strings
.
ToLower
(
rs
)
}
if
exactMatch
{
match
:=
matchPattern
(
rs
,
ls
)
...
...
@@ -3649,7 +3649,15 @@ func compareFormulaArg(lhs, rhs formulaArg, caseSensitive, exactMatch bool) byte
}
return
criteriaG
}
return
byte
(
strings
.
Compare
(
ls
,
rs
))
switch
strings
.
Compare
(
ls
,
rs
)
{
case
1
:
return
criteriaG
case
-
1
:
return
criteriaL
case
0
:
return
criteriaEq
}
return
criteriaErr
case
ArgEmpty
:
return
criteriaEq
case
ArgList
:
...
...
@@ -3739,16 +3747,29 @@ func (fn *formulaFuncs) HLOOKUP(argsList *list.List) formulaArg {
}
}
row
:=
tableArray
.
Matrix
[
0
]
start
:
for
idx
,
mtx
:=
range
row
{
switch
compareFormulaArg
(
mtx
,
lookupValue
,
false
,
exactMatch
)
{
case
criteriaL
:
matchIdx
=
idx
case
criteriaEq
:
matchIdx
=
idx
wasExact
=
true
break
start
if
exactMatch
||
len
(
tableArray
.
Matrix
)
==
TotalRows
{
start
:
for
idx
,
mtx
:=
range
row
{
lhs
:=
mtx
switch
lookupValue
.
Type
{
case
ArgNumber
:
if
!
lookupValue
.
Boolean
{
lhs
=
mtx
.
ToNumber
()
if
lhs
.
Type
==
ArgError
{
lhs
=
mtx
}
}
case
ArgMatrix
:
lhs
=
tableArray
}
if
compareFormulaArg
(
lhs
,
lookupValue
,
false
,
exactMatch
)
==
criteriaEq
{
matchIdx
=
idx
wasExact
=
true
break
start
}
}
}
else
{
matchIdx
,
wasExact
=
hlookupBinarySearch
(
row
,
lookupValue
)
}
if
matchIdx
==
-
1
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"HLOOKUP no result found"
)
...
...
@@ -3795,11 +3816,51 @@ func (fn *formulaFuncs) VLOOKUP(argsList *list.List) formulaArg {
exactMatch
=
true
}
}
start
:
for
idx
,
mtx
:=
range
tableArray
.
Matrix
{
if
len
(
mtx
)
==
0
{
continue
if
exactMatch
||
len
(
tableArray
.
Matrix
)
==
TotalRows
{
start
:
for
idx
,
mtx
:=
range
tableArray
.
Matrix
{
lhs
:=
mtx
[
0
]
switch
lookupValue
.
Type
{
case
ArgNumber
:
if
!
lookupValue
.
Boolean
{
lhs
=
mtx
[
0
]
.
ToNumber
()
if
lhs
.
Type
==
ArgError
{
lhs
=
mtx
[
0
]
}
}
case
ArgMatrix
:
lhs
=
tableArray
}
if
compareFormulaArg
(
lhs
,
lookupValue
,
false
,
exactMatch
)
==
criteriaEq
{
matchIdx
=
idx
wasExact
=
true
break
start
}
}
}
else
{
matchIdx
,
wasExact
=
vlookupBinarySearch
(
tableArray
,
lookupValue
)
}
if
matchIdx
==
-
1
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP no result found"
)
}
mtx
:=
tableArray
.
Matrix
[
matchIdx
]
if
col
<
0
||
col
>=
len
(
mtx
)
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP has invalid column index"
)
}
if
wasExact
||
!
exactMatch
{
return
mtx
[
col
]
}
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP no result found"
)
}
// vlookupBinarySearch finds the position of a target value when range lookup
// is TRUE, if the data of table array can't guarantee be sorted, it will
// return wrong result.
func
vlookupBinarySearch
(
tableArray
,
lookupValue
formulaArg
)
(
matchIdx
int
,
wasExact
bool
)
{
var
low
,
high
,
lastMatchIdx
int
=
0
,
len
(
tableArray
.
Matrix
)
-
1
,
-
1
for
low
<=
high
{
var
mid
int
=
low
+
(
high
-
low
)
/
2
mtx
:=
tableArray
.
Matrix
[
mid
]
lhs
:=
mtx
[
0
]
switch
lookupValue
.
Type
{
case
ArgNumber
:
...
...
@@ -3812,24 +3873,106 @@ start:
case
ArgMatrix
:
lhs
=
tableArray
}
switch
compareFormulaArg
(
lhs
,
lookupValue
,
false
,
exactMatch
)
{
case
criteriaL
:
matchIdx
=
idx
case
criteriaEq
:
result
:=
compareFormulaArg
(
lhs
,
lookupValue
,
false
,
false
)
if
result
==
criteriaEq
{
matchIdx
,
wasExact
=
mid
,
true
return
}
else
if
result
==
criteriaG
{
high
=
mid
-
1
}
else
if
result
==
criteriaL
{
matchIdx
,
low
=
mid
,
mid
+
1
if
lhs
.
Value
()
!=
""
{
lastMatchIdx
=
matchIdx
}
}
else
{
return
-
1
,
false
}
}
matchIdx
,
wasExact
=
lastMatchIdx
,
true
return
}
// vlookupBinarySearch finds the position of a target value when range lookup
// is TRUE, if the data of table array can't guarantee be sorted, it will
// return wrong result.
func
hlookupBinarySearch
(
row
[]
formulaArg
,
lookupValue
formulaArg
)
(
matchIdx
int
,
wasExact
bool
)
{
var
low
,
high
,
lastMatchIdx
int
=
0
,
len
(
row
)
-
1
,
-
1
for
low
<=
high
{
var
mid
int
=
low
+
(
high
-
low
)
/
2
mtx
:=
row
[
mid
]
result
:=
compareFormulaArg
(
mtx
,
lookupValue
,
false
,
false
)
if
result
==
criteriaEq
{
matchIdx
,
wasExact
=
mid
,
true
return
}
else
if
result
==
criteriaG
{
high
=
mid
-
1
}
else
if
result
==
criteriaL
{
low
,
lastMatchIdx
=
mid
+
1
,
mid
}
else
{
return
-
1
,
false
}
}
matchIdx
,
wasExact
=
lastMatchIdx
,
true
return
}
// LOOKUP function performs an approximate match lookup in a one-column or
// one-row range, and returns the corresponding value from another one-column
// or one-row range. The syntax of the function is:
//
// LOOKUP(lookup_value,lookup_vector,[result_vector])
//
func
(
fn
*
formulaFuncs
)
LOOKUP
(
argsList
*
list
.
List
)
formulaArg
{
if
argsList
.
Len
()
<
2
{
return
newErrorFormulaArg
(
formulaErrorVALUE
,
"LOOKUP requires at least 2 arguments"
)
}
if
argsList
.
Len
()
>
3
{
return
newErrorFormulaArg
(
formulaErrorVALUE
,
"LOOKUP requires at most 3 arguments"
)
}
lookupValue
:=
argsList
.
Front
()
.
Value
.
(
formulaArg
)
lookupVector
:=
argsList
.
Front
()
.
Next
()
.
Value
.
(
formulaArg
)
if
lookupVector
.
Type
!=
ArgMatrix
&&
lookupVector
.
Type
!=
ArgList
{
return
newErrorFormulaArg
(
formulaErrorVALUE
,
"LOOKUP requires second argument of table array"
)
}
cols
,
matchIdx
:=
lookupCol
(
lookupVector
),
-
1
for
idx
,
col
:=
range
cols
{
lhs
:=
lookupValue
switch
col
.
Type
{
case
ArgNumber
:
lhs
=
lhs
.
ToNumber
()
if
!
col
.
Boolean
{
if
lhs
.
Type
==
ArgError
{
lhs
=
lookupValue
}
}
}
if
compareFormulaArg
(
lhs
,
col
,
false
,
false
)
==
criteriaEq
{
matchIdx
=
idx
wasExact
=
true
break
start
break
}
}
if
matchIdx
==
-
1
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP no result found"
)
column
:=
cols
if
argsList
.
Len
()
==
3
{
column
=
lookupCol
(
argsList
.
Back
()
.
Value
.
(
formulaArg
))
}
mtx
:=
tableArray
.
Matrix
[
matchIdx
]
if
col
<
0
||
col
>=
len
(
mtx
)
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP has invalid column index"
)
if
matchIdx
<
0
||
matchIdx
>=
len
(
column
)
{
return
newErrorFormulaArg
(
formulaErrorNA
,
"LOOKUP no result found"
)
}
if
wasExact
||
!
exactMatch
{
return
mtx
[
col
]
return
column
[
matchIdx
]
}
// lookupCol extract columns for LOOKUP.
func
lookupCol
(
arr
formulaArg
)
[]
formulaArg
{
col
:=
arr
.
List
if
arr
.
Type
==
ArgMatrix
{
col
=
nil
for
_
,
r
:=
range
arr
.
Matrix
{
if
len
(
r
)
>
0
{
col
=
append
(
col
,
r
[
0
])
continue
}
col
=
append
(
col
,
newEmptyFormulaArg
())
}
}
return
newErrorFormulaArg
(
formulaErrorNA
,
"VLOOKUP no result found"
)
return
col
}
calc_test.go
浏览文件 @
ec45d67e
...
...
@@ -10,6 +10,17 @@ import (
"github.com/xuri/efp"
)
func
prepareCalcData
(
cellData
[][]
interface
{})
*
File
{
f
:=
NewFile
()
for
r
,
row
:=
range
cellData
{
for
c
,
value
:=
range
row
{
cell
,
_
:=
CoordinatesToCellName
(
c
+
1
,
r
+
1
)
f
.
SetCellValue
(
"Sheet1"
,
cell
,
value
)
}
}
return
f
}
func
TestCalcCellValue
(
t
*
testing
.
T
)
{
cellData
:=
[][]
interface
{}{
{
1
,
4
,
nil
,
"Month"
,
"Team"
,
"Sales"
},
...
...
@@ -22,17 +33,6 @@ func TestCalcCellValue(t *testing.T) {
{
nil
,
nil
,
nil
,
"Feb"
,
"South 1"
,
32080
},
{
nil
,
nil
,
nil
,
"Feb"
,
"South 2"
,
45500
},
}
prepareData
:=
func
()
*
File
{
f
:=
NewFile
()
for
r
,
row
:=
range
cellData
{
for
c
,
value
:=
range
row
{
cell
,
_
:=
CoordinatesToCellName
(
c
+
1
,
r
+
1
)
assert
.
NoError
(
t
,
f
.
SetCellValue
(
"Sheet1"
,
cell
,
value
))
}
}
return
f
}
mathCalc
:=
map
[
string
]
string
{
"=2^3"
:
"8"
,
"=1=1"
:
"TRUE"
,
...
...
@@ -562,18 +562,28 @@ func TestCalcCellValue(t *testing.T) {
"=CHOOSE(1,
\"
red
\"
,
\"
blue
\"
,
\"
green
\"
,
\"
brown
\"
)"
:
"red"
,
"=SUM(CHOOSE(A2,A1,B1:B2,A1:A3,A1:A4))"
:
"9"
,
// HLOOKUP
"=HLOOKUP(D2,D2:D8,1,FALSE)"
:
"Jan"
,
"=HLOOKUP(F3,F3:F8,3,FALSE)"
:
"34440"
,
// should be Feb
"=HLOOKUP(D2,D2:D8,1,FALSE)"
:
"Jan"
,
"=HLOOKUP(F3,F3:F8,3,FALSE)"
:
"34440"
,
"=HLOOKUP(INT(F3),F3:F8,3,FALSE)"
:
"34440"
,
"=HLOOKUP(MUNIT(1),MUNIT(1),1,FALSE)"
:
"1"
,
// VLOOKUP
"=VLOOKUP(D2,D:D,1,FALSE)"
:
"Jan"
,
"=VLOOKUP(D2,D:D,1,TRUE)"
:
"Month"
,
// should be Feb
"=VLOOKUP(INT(36693),F2:F2,1,FALSE)"
:
"36693"
,
"=VLOOKUP(INT(F2),F3:F9,1)"
:
"32080"
,
"=VLOOKUP(MUNIT(3),MUNIT(2),1)"
:
"0"
,
// should be 1
"=VLOOKUP(MUNIT(3),MUNIT(3),1)"
:
"1"
,
"=VLOOKUP(D2,D:D,1,FALSE)"
:
"Jan"
,
"=VLOOKUP(D2,D1:D10,1)"
:
"Jan"
,
"=VLOOKUP(D2,D1:D11,1)"
:
"Feb"
,
"=VLOOKUP(D2,D1:D10,1,FALSE)"
:
"Jan"
,
"=VLOOKUP(INT(36693),F2:F2,1,FALSE)"
:
"36693"
,
"=VLOOKUP(INT(F2),F3:F9,1)"
:
"32080"
,
"=VLOOKUP(INT(F2),F3:F9,1,TRUE)"
:
"32080"
,
"=VLOOKUP(MUNIT(3),MUNIT(3),1)"
:
"0"
,
"=VLOOKUP(A1,A3:B5,1)"
:
"0"
,
"=VLOOKUP(MUNIT(1),MUNIT(1),1,FALSE)"
:
"1"
,
// LOOKUP
"=LOOKUP(F8,F8:F9,F8:F9)"
:
"32080"
,
"=LOOKUP(F8,F8:F9,D8:D9)"
:
"Feb"
,
"=LOOKUP(1,MUNIT(1),MUNIT(1))"
:
"1"
,
}
for
formula
,
expected
:=
range
mathCalc
{
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
NoError
(
t
,
err
,
formula
)
...
...
@@ -759,8 +769,9 @@ func TestCalcCellValue(t *testing.T) {
// MULTINOMIAL
`=MULTINOMIAL("X")`
:
"strconv.ParseFloat: parsing
\"
X
\"
: invalid syntax"
,
// _xlfn.MUNIT
"=_xlfn.MUNIT()"
:
"MUNIT requires 1 numeric argument"
,
// not support currently
`=_xlfn.MUNIT("X")`
:
"strconv.ParseFloat: parsing
\"
X
\"
: invalid syntax"
,
// not support currently
"=_xlfn.MUNIT()"
:
"MUNIT requires 1 numeric argument"
,
`=_xlfn.MUNIT("X")`
:
"strconv.ParseFloat: parsing
\"
X
\"
: invalid syntax"
,
"=_xlfn.MUNIT(-1)"
:
""
,
// ODD
"=ODD()"
:
"ODD requires 1 numeric argument"
,
`=ODD("X")`
:
"strconv.ParseFloat: parsing
\"
X
\"
: invalid syntax"
,
...
...
@@ -947,10 +958,15 @@ func TestCalcCellValue(t *testing.T) {
"=VLOOKUP(ISNUMBER(1),F3:F9,1)"
:
"VLOOKUP no result found"
,
"=VLOOKUP(INT(1),E2:E9,1)"
:
"VLOOKUP no result found"
,
"=VLOOKUP(MUNIT(2),MUNIT(3),1)"
:
"VLOOKUP no result found"
,
"=VLOOKUP(A1:B2,B2:B3,1)"
:
"VLOOKUP no result found"
,
"=VLOOKUP(1,G1:H2,1,FALSE)"
:
"VLOOKUP no result found"
,
// LOOKUP
"=LOOKUP()"
:
"LOOKUP requires at least 2 arguments"
,
"=LOOKUP(D2,D1,D2)"
:
"LOOKUP requires second argument of table array"
,
"=LOOKUP(D2,D1,D2,FALSE)"
:
"LOOKUP requires at most 3 arguments"
,
"=LOOKUP(D1,MUNIT(1),MUNIT(1))"
:
"LOOKUP no result found"
,
}
for
formula
,
expected
:=
range
mathCalcError
{
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
EqualError
(
t
,
err
,
expected
,
formula
)
...
...
@@ -974,7 +990,7 @@ func TestCalcCellValue(t *testing.T) {
"=A1/A2/SUM(A1:A2:B1)*A3"
:
"0.125"
,
}
for
formula
,
expected
:=
range
referenceCalc
{
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
NoError
(
t
,
err
)
...
...
@@ -988,7 +1004,7 @@ func TestCalcCellValue(t *testing.T) {
"=1+SUM(SUM(A1+A2/A4)*(2-3),2)"
:
"#DIV/0!"
,
}
for
formula
,
expected
:=
range
referenceCalcError
{
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
EqualError
(
t
,
err
,
expected
)
...
...
@@ -1000,23 +1016,23 @@ func TestCalcCellValue(t *testing.T) {
"=RANDBETWEEN(1,2)"
,
}
for
_
,
formula
:=
range
volatileFuncs
{
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
formula
))
_
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
NoError
(
t
,
err
)
}
// Test get calculated cell value on not formula cell.
f
:=
prepare
Data
(
)
f
:=
prepare
CalcData
(
cellData
)
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"A1"
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
""
,
result
)
// Test get calculated cell value on not exists worksheet.
f
=
prepare
Data
(
)
f
=
prepare
CalcData
(
cellData
)
_
,
err
=
f
.
CalcCellValue
(
"SheetN"
,
"A1"
)
assert
.
EqualError
(
t
,
err
,
"sheet SheetN is not exist"
)
// Test get calculated cell value with not support formula.
f
=
prepare
Data
(
)
f
=
prepare
CalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"A1"
,
"=UNSUPPORT(A1)"
))
_
,
err
=
f
.
CalcCellValue
(
"Sheet1"
,
"A1"
)
assert
.
EqualError
(
t
,
err
,
"not support UNSUPPORT function"
)
...
...
@@ -1036,24 +1052,13 @@ func TestCalculate(t *testing.T) {
assert
.
EqualError
(
t
,
calculate
(
opd
,
opt
),
err
)
}
func
TestCalc
CellValue
WithDefinedName
(
t
*
testing
.
T
)
{
func
TestCalcWithDefinedName
(
t
*
testing
.
T
)
{
cellData
:=
[][]
interface
{}{
{
"A1 value"
,
"B1 value"
,
nil
},
}
prepareData
:=
func
()
*
File
{
f
:=
NewFile
()
for
r
,
row
:=
range
cellData
{
for
c
,
value
:=
range
row
{
cell
,
_
:=
CoordinatesToCellName
(
c
+
1
,
r
+
1
)
assert
.
NoError
(
t
,
f
.
SetCellValue
(
"Sheet1"
,
cell
,
value
))
}
}
assert
.
NoError
(
t
,
f
.
SetDefinedName
(
&
DefinedName
{
Name
:
"defined_name1"
,
RefersTo
:
"Sheet1!A1"
,
Scope
:
"Workbook"
}))
assert
.
NoError
(
t
,
f
.
SetDefinedName
(
&
DefinedName
{
Name
:
"defined_name1"
,
RefersTo
:
"Sheet1!B1"
,
Scope
:
"Sheet1"
}))
return
f
}
f
:=
prepareData
()
f
:=
prepareCalcData
(
cellData
)
assert
.
NoError
(
t
,
f
.
SetDefinedName
(
&
DefinedName
{
Name
:
"defined_name1"
,
RefersTo
:
"Sheet1!A1"
,
Scope
:
"Workbook"
}))
assert
.
NoError
(
t
,
f
.
SetDefinedName
(
&
DefinedName
{
Name
:
"defined_name1"
,
RefersTo
:
"Sheet1!B1"
,
Scope
:
"Sheet1"
}))
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"C1"
,
"=defined_name1"
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"C1"
)
assert
.
NoError
(
t
,
err
)
...
...
@@ -1061,7 +1066,7 @@ func TestCalcCellValueWithDefinedName(t *testing.T) {
assert
.
Equal
(
t
,
"B1 value"
,
result
,
"=defined_name1"
)
}
func
TestCalc
Pow
(
t
*
testing
.
T
)
{
func
TestCalc
ArithmeticOperations
(
t
*
testing
.
T
)
{
err
:=
`strconv.ParseFloat: parsing "text": invalid syntax`
assert
.
EqualError
(
t
,
calcPow
(
"1"
,
"text"
,
nil
),
err
)
assert
.
EqualError
(
t
,
calcPow
(
"text"
,
"1"
,
nil
),
err
)
...
...
@@ -1085,7 +1090,7 @@ func TestCalcPow(t *testing.T) {
assert
.
EqualError
(
t
,
calcDiv
(
"text"
,
"1"
,
nil
),
err
)
}
func
TestISBLANK
(
t
*
testing
.
T
)
{
func
Test
Calc
ISBLANK
(
t
*
testing
.
T
)
{
argsList
:=
list
.
New
()
argsList
.
PushBack
(
formulaArg
{
Type
:
ArgUnknown
,
...
...
@@ -1096,7 +1101,7 @@ func TestISBLANK(t *testing.T) {
assert
.
Empty
(
t
,
result
.
Error
)
}
func
TestAND
(
t
*
testing
.
T
)
{
func
Test
Calc
AND
(
t
*
testing
.
T
)
{
argsList
:=
list
.
New
()
argsList
.
PushBack
(
formulaArg
{
Type
:
ArgUnknown
,
...
...
@@ -1107,7 +1112,7 @@ func TestAND(t *testing.T) {
assert
.
Empty
(
t
,
result
.
Error
)
}
func
TestOR
(
t
*
testing
.
T
)
{
func
Test
Calc
OR
(
t
*
testing
.
T
)
{
argsList
:=
list
.
New
()
argsList
.
PushBack
(
formulaArg
{
Type
:
ArgUnknown
,
...
...
@@ -1118,7 +1123,7 @@ func TestOR(t *testing.T) {
assert
.
Empty
(
t
,
result
.
Error
)
}
func
TestDet
(
t
*
testing
.
T
)
{
func
Test
Calc
Det
(
t
*
testing
.
T
)
{
assert
.
Equal
(
t
,
det
([][]
float64
{
{
1
,
2
,
3
,
4
},
{
2
,
3
,
4
,
5
},
...
...
@@ -1127,7 +1132,12 @@ func TestDet(t *testing.T) {
}),
float64
(
0
))
}
func
TestCompareFormulaArg
(
t
*
testing
.
T
)
{
func
TestCalcToBool
(
t
*
testing
.
T
)
{
b
:=
newBoolFormulaArg
(
true
)
.
ToBool
()
assert
.
Equal
(
t
,
b
.
Boolean
,
true
)
assert
.
Equal
(
t
,
b
.
Number
,
1.0
)
}
func
TestCalcCompareFormulaArg
(
t
*
testing
.
T
)
{
assert
.
Equal
(
t
,
compareFormulaArg
(
newEmptyFormulaArg
(),
newEmptyFormulaArg
(),
false
,
false
),
criteriaEq
)
lhs
:=
newListFormulaArg
([]
formulaArg
{
newEmptyFormulaArg
()})
rhs
:=
newListFormulaArg
([]
formulaArg
{
newEmptyFormulaArg
(),
newEmptyFormulaArg
()})
...
...
@@ -1141,9 +1151,82 @@ func TestCompareFormulaArg(t *testing.T) {
assert
.
Equal
(
t
,
compareFormulaArg
(
formulaArg
{
Type
:
ArgUnknown
},
formulaArg
{
Type
:
ArgUnknown
},
false
,
false
),
criteriaErr
)
}
func
TestMatchPattern
(
t
*
testing
.
T
)
{
func
Test
Calc
MatchPattern
(
t
*
testing
.
T
)
{
assert
.
True
(
t
,
matchPattern
(
""
,
""
))
assert
.
True
(
t
,
matchPattern
(
"file/*"
,
"file/abc/bcd/def"
))
assert
.
True
(
t
,
matchPattern
(
"*"
,
""
))
assert
.
False
(
t
,
matchPattern
(
"file/?"
,
"file/abc/bcd/def"
))
}
func
TestCalcVLOOKUP
(
t
*
testing
.
T
)
{
cellData
:=
[][]
interface
{}{
{
nil
,
nil
,
nil
,
nil
,
nil
,
nil
},
{
nil
,
"Score"
,
"Grade"
,
nil
,
nil
,
nil
},
{
nil
,
0
,
"F"
,
nil
,
"Score"
,
85
},
{
nil
,
60
,
"D"
,
nil
,
"Grade"
},
{
nil
,
70
,
"C"
,
nil
,
nil
,
nil
},
{
nil
,
80
,
"b"
,
nil
,
nil
,
nil
},
{
nil
,
90
,
"A"
,
nil
,
nil
,
nil
},
{
nil
,
85
,
"B"
,
nil
,
nil
,
nil
},
{
nil
,
nil
,
nil
,
nil
,
nil
,
nil
},
}
f
:=
prepareCalcData
(
cellData
)
calc
:=
map
[
string
]
string
{
"=VLOOKUP(F3,B3:C8,2)"
:
"b"
,
"=VLOOKUP(F3,B3:C8,2,TRUE)"
:
"b"
,
"=VLOOKUP(F3,B3:C8,2,FALSE)"
:
"B"
,
}
for
formula
,
expected
:=
range
calc
{
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"F4"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"F4"
)
assert
.
NoError
(
t
,
err
,
formula
)
assert
.
Equal
(
t
,
expected
,
result
,
formula
)
}
calcError
:=
map
[
string
]
string
{
"=VLOOKUP(INT(1),C3:C3,1,FALSE)"
:
"VLOOKUP no result found"
,
}
for
formula
,
expected
:=
range
calcError
{
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"F4"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"F4"
)
assert
.
EqualError
(
t
,
err
,
expected
,
formula
)
assert
.
Equal
(
t
,
""
,
result
,
formula
)
}
}
func
TestCalcHLOOKUP
(
t
*
testing
.
T
)
{
cellData
:=
[][]
interface
{}{
{
"Example Result Table"
},
{
nil
,
"A"
,
"B"
,
"C"
,
"E"
,
"F"
},
{
"Math"
,
.58
,
.9
,
.67
,
.76
,
.8
},
{
"French"
,
.61
,
.71
,
.59
,
.59
,
.76
},
{
"Physics"
,
.75
,
.45
,
.39
,
.52
,
.69
},
{
"Biology"
,
.39
,
.55
,
.77
,
.61
,
.45
},
{},
{
"Individual Student Score"
},
{
"Student:"
,
"Biology Score:"
},
{
"E"
},
}
f
:=
prepareCalcData
(
cellData
)
formulaList
:=
map
[
string
]
string
{
"=HLOOKUP(A10,A2:F6,5,FALSE)"
:
"0.61"
,
"=HLOOKUP(D3,D3:D3,1,TRUE)"
:
"0.67"
,
"=HLOOKUP(F3,D3:F3,1,TRUE)"
:
"0.8"
,
"=HLOOKUP(A5,A2:F2,1,TRUE)"
:
"F"
,
"=HLOOKUP(
\"
D
\"
,A2:F2,1,TRUE)"
:
"C"
,
}
for
formula
,
expected
:=
range
formulaList
{
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"B10"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"B10"
)
assert
.
NoError
(
t
,
err
,
formula
)
assert
.
Equal
(
t
,
expected
,
result
,
formula
)
}
calcError
:=
map
[
string
]
string
{
"=HLOOKUP(INT(1),A3:A3,1,FALSE)"
:
"HLOOKUP no result found"
,
}
for
formula
,
expected
:=
range
calcError
{
assert
.
NoError
(
t
,
f
.
SetCellFormula
(
"Sheet1"
,
"B10"
,
formula
))
result
,
err
:=
f
.
CalcCellValue
(
"Sheet1"
,
"B10"
)
assert
.
EqualError
(
t
,
err
,
expected
,
formula
)
assert
.
Equal
(
t
,
""
,
result
,
formula
)
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录