Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
此号慢热型
excelize
提交
b84bd1ab
excelize
项目概览
此号慢热型
/
excelize
与 Fork 源项目一致
Fork自
xuri / excelize
通知
2
Star
0
Fork
0
代码
文件
提交
分支
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 搜索 >>
已验证
提交
b84bd1ab
编写于
1月 27, 2021
作者:
xurime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
new formula fn: IF, LEN; not equal operator support and faster numeric precision process
上级
e568319b
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
121 addition
and
21 deletion
+121
-21
calc.go
calc.go
+65
-5
calc_test.go
calc_test.go
+20
-4
lib.go
lib.go
+25
-2
rows.go
rows.go
+3
-7
rows_test.go
rows_test.go
+8
-3
未找到文件。
calc.go
浏览文件 @
b84bd1ab
...
...
@@ -110,6 +110,7 @@ var tokenPriority = map[string]int{
"+"
:
3
,
"-"
:
3
,
"="
:
2
,
"<>"
:
2
,
"<"
:
2
,
"<="
:
2
,
">"
:
2
,
...
...
@@ -151,11 +152,9 @@ func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
return
}
result
=
token
.
TValue
if
len
(
result
)
>
16
{
num
,
e
:=
roundPrecision
(
result
)
if
e
!=
nil
{
return
result
,
err
}
isNum
,
precision
:=
isNumeric
(
result
)
if
isNum
&&
precision
>
15
{
num
,
_
:=
roundPrecision
(
result
)
result
=
strings
.
ToUpper
(
num
)
}
return
...
...
@@ -353,6 +352,12 @@ func calcEq(rOpd, lOpd string, opdStack *Stack) error {
return
nil
}
// calcNEq evaluate not equal arithmetic operations.
func
calcNEq
(
rOpd
,
lOpd
string
,
opdStack
*
Stack
)
error
{
opdStack
.
Push
(
efp
.
Token
{
TValue
:
strings
.
ToUpper
(
strconv
.
FormatBool
(
rOpd
!=
lOpd
)),
TType
:
efp
.
TokenTypeOperand
,
TSubType
:
efp
.
TokenSubTypeNumber
})
return
nil
}
// calcL evaluate less than arithmetic operations.
func
calcL
(
rOpd
,
lOpd
string
,
opdStack
*
Stack
)
error
{
lOpdVal
,
err
:=
strconv
.
ParseFloat
(
lOpd
,
64
)
...
...
@@ -498,6 +503,7 @@ func calculate(opdStack *Stack, opt efp.Token) error {
"/"
:
calcDiv
,
"+"
:
calcAdd
,
"="
:
calcEq
,
"<>"
:
calcNEq
,
"<"
:
calcL
,
"<="
:
calcLe
,
">"
:
calcG
,
...
...
@@ -3400,6 +3406,20 @@ func (fn *formulaFuncs) CLEAN(argsList *list.List) (result string, err error) {
return
}
// LEN returns the length of a supplied text string. The syntax of the
// function is:
//
// LEN(text)
//
func
(
fn
*
formulaFuncs
)
LEN
(
argsList
*
list
.
List
)
(
result
string
,
err
error
)
{
if
argsList
.
Len
()
!=
1
{
err
=
errors
.
New
(
"LEN requires 1 string argument"
)
return
}
result
=
strconv
.
Itoa
(
len
(
argsList
.
Front
()
.
Value
.
(
formulaArg
)
.
String
))
return
}
// TRIM removes extra spaces (i.e. all spaces except for single spaces between
// words or characters) from a supplied text string. The syntax of the
// function is:
...
...
@@ -3469,3 +3489,43 @@ func (fn *formulaFuncs) UPPER(argsList *list.List) (result string, err error) {
result
=
strings
.
ToUpper
(
argsList
.
Front
()
.
Value
.
(
formulaArg
)
.
String
)
return
}
// Conditional Functions
// IF function tests a supplied condition and returns one result if the
// condition evaluates to TRUE, and another result if the condition evaluates
// to FALSE. The syntax of the function is:
//
// IF( logical_test, value_if_true, value_if_false )
//
func
(
fn
*
formulaFuncs
)
IF
(
argsList
*
list
.
List
)
(
result
string
,
err
error
)
{
if
argsList
.
Len
()
==
0
{
err
=
errors
.
New
(
"IF requires at least 1 argument"
)
return
}
if
argsList
.
Len
()
>
3
{
err
=
errors
.
New
(
"IF accepts at most 3 arguments"
)
return
}
token
:=
argsList
.
Front
()
.
Value
.
(
formulaArg
)
var
cond
bool
switch
token
.
Type
{
case
ArgString
:
if
cond
,
err
=
strconv
.
ParseBool
(
token
.
String
);
err
!=
nil
{
err
=
errors
.
New
(
formulaErrorVALUE
)
return
}
if
argsList
.
Len
()
==
1
{
result
=
strings
.
ToUpper
(
strconv
.
FormatBool
(
cond
))
return
}
if
cond
{
result
=
argsList
.
Front
()
.
Next
()
.
Value
.
(
formulaArg
)
.
String
return
}
if
argsList
.
Len
()
==
3
{
result
=
argsList
.
Back
()
.
Value
.
(
formulaArg
)
.
String
}
}
return
}
calc_test.go
浏览文件 @
b84bd1ab
...
...
@@ -323,13 +323,13 @@ func TestCalcCellValue(t *testing.T) {
"=ROUND(991,-1)"
:
"990"
,
// ROUNDDOWN
"=ROUNDDOWN(99.999,1)"
:
"99.9"
,
"=ROUNDDOWN(99.999,2)"
:
"99.9900000000000
1
"
,
"=ROUNDDOWN(99.999,2)"
:
"99.9900000000000
2
"
,
"=ROUNDDOWN(99.999,0)"
:
"99"
,
"=ROUNDDOWN(99.999,-1)"
:
"90"
,
"=ROUNDDOWN(-99.999,2)"
:
"-99.9900000000000
1
"
,
"=ROUNDDOWN(-99.999,2)"
:
"-99.9900000000000
2
"
,
"=ROUNDDOWN(-99.999,-1)"
:
"-90"
,
// ROUNDUP
"=ROUNDUP(11.111,1)"
:
"11.20000000000000
3
"
,
// ROUNDUP
`
"=ROUNDUP(11.111,1)"
:
"11.20000000000000
1
"
,
"=ROUNDUP(11.111,2)"
:
"11.120000000000003"
,
"=ROUNDUP(11.111,0)"
:
"12"
,
"=ROUNDUP(11.111,-1)"
:
"20"
,
...
...
@@ -467,6 +467,9 @@ func TestCalcCellValue(t *testing.T) {
// CLEAN
"=CLEAN(
\"\u0009
clean text
\"
)"
:
"clean text"
,
"=CLEAN(0)"
:
"0"
,
// LEN
"=LEN(
\"\"
)"
:
"0"
,
"=LEN(D1)"
:
"5"
,
// TRIM
"=TRIM(
\"
trim text
\"
)"
:
"trim text"
,
"=TRIM(0)"
:
"0"
,
...
...
@@ -485,6 +488,12 @@ func TestCalcCellValue(t *testing.T) {
"=UPPER(
\"
TEST
\"
)"
:
"TEST"
,
"=UPPER(
\"
Test
\"
)"
:
"TEST"
,
"=UPPER(
\"
TEST 123
\"
)"
:
"TEST 123"
,
// Conditional Functions
// IF
"=IF(1=1)"
:
"TRUE"
,
"=IF(1<>1)"
:
"FALSE"
,
"=IF(5<0,
\"
negative
\"
,
\"
positive
\"
)"
:
"positive"
,
"=IF(-2<0,
\"
negative
\"
,
\"
positive
\"
)"
:
"negative"
,
}
for
formula
,
expected
:=
range
mathCalc
{
f
:=
prepareData
()
...
...
@@ -805,6 +814,8 @@ func TestCalcCellValue(t *testing.T) {
// CLEAN
"=CLEAN()"
:
"CLEAN requires 1 argument"
,
"=CLEAN(1,2)"
:
"CLEAN requires 1 argument"
,
// LEN
"=LEN()"
:
"LEN requires 1 string argument"
,
// TRIM
"=TRIM()"
:
"TRIM requires 1 argument"
,
"=TRIM(1,2)"
:
"TRIM requires 1 argument"
,
...
...
@@ -817,6 +828,11 @@ func TestCalcCellValue(t *testing.T) {
// PROPER
"=PROPER()"
:
"PROPER requires 1 argument"
,
"=PROPER(1,2)"
:
"PROPER requires 1 argument"
,
// Conditional Functions
// IF
"=IF()"
:
"IF requires at least 1 argument"
,
"=IF(0,1,2,3)"
:
"IF accepts at most 3 arguments"
,
"=IF(D1,1,2)"
:
"#VALUE!"
,
}
for
formula
,
expected
:=
range
mathCalcError
{
f
:=
prepareData
()
...
...
lib.go
浏览文件 @
b84bd1ab
...
...
@@ -403,8 +403,8 @@ func (f *File) addNameSpaces(path string, ns xml.Attr) {
}
}
// setIgnorableNameSpace provides a function to set XML namespace as ignorable
by the given
// attribute.
// setIgnorableNameSpace provides a function to set XML namespace as ignorable
//
by the given
attribute.
func
(
f
*
File
)
setIgnorableNameSpace
(
path
string
,
index
int
,
ns
xml
.
Attr
)
{
ignorableNS
:=
[]
string
{
"c14"
,
"cdr14"
,
"a14"
,
"pic14"
,
"x14"
,
"xdr14"
,
"x14ac"
,
"dsp"
,
"mso14"
,
"dgm14"
,
"x15"
,
"x12ac"
,
"x15ac"
,
"xr"
,
"xr2"
,
"xr3"
,
"xr4"
,
"xr5"
,
"xr6"
,
"xr7"
,
"xr8"
,
"xr9"
,
"xr10"
,
"xr11"
,
"xr12"
,
"xr13"
,
"xr14"
,
"xr15"
,
"x15"
,
"x16"
,
"x16r2"
,
"mo"
,
"mx"
,
"mv"
,
"o"
,
"v"
}
if
inStrSlice
(
strings
.
Fields
(
f
.
xmlAttr
[
path
][
index
]
.
Value
),
ns
.
Name
.
Local
)
==
-
1
&&
inStrSlice
(
ignorableNS
,
ns
.
Name
.
Local
)
!=
-
1
{
...
...
@@ -418,6 +418,29 @@ func (f *File) addSheetNameSpace(sheet string, ns xml.Attr) {
f
.
addNameSpaces
(
name
,
ns
)
}
// isNumeric determines whether an expression is a valid numeric type and get
// the precision for the numeric.
func
isNumeric
(
s
string
)
(
bool
,
int
)
{
dot
:=
false
p
:=
0
for
i
,
v
:=
range
s
{
if
v
==
'.'
{
if
dot
{
return
false
,
0
}
dot
=
true
}
else
if
v
<
'0'
||
v
>
'9'
{
if
i
==
0
&&
v
==
'-'
{
continue
}
return
false
,
0
}
else
if
dot
{
p
++
}
}
return
true
,
p
}
// Stack defined an abstract data type that serves as a collection of elements.
type
Stack
struct
{
list
*
list
.
List
...
...
rows.go
浏览文件 @
b84bd1ab
...
...
@@ -20,7 +20,6 @@ import (
"log"
"math"
"strconv"
"strings"
"github.com/mohae/deepcopy"
)
...
...
@@ -346,12 +345,9 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
}
return
f
.
formattedValue
(
c
.
S
,
c
.
V
),
nil
default
:
splited
:=
strings
.
Split
(
c
.
V
,
"."
)
if
len
(
splited
)
==
2
&&
len
(
splited
[
1
])
>
15
{
val
,
err
:=
roundPrecision
(
c
.
V
)
if
err
!=
nil
{
return
""
,
err
}
isNum
,
precision
:=
isNumeric
(
c
.
V
)
if
isNum
&&
precision
>
15
{
val
,
_
:=
roundPrecision
(
c
.
V
)
if
val
!=
c
.
V
{
return
f
.
formattedValue
(
c
.
S
,
val
),
nil
}
...
...
rows_test.go
浏览文件 @
b84bd1ab
...
...
@@ -835,9 +835,14 @@ func TestGetValueFromNumber(t *testing.T) {
assert
.
Equal
(
t
,
"2.22"
,
val
)
c
=
&
xlsxC
{
T
:
"n"
,
V
:
"2.220000ddsf0000000002-r"
}
_
,
err
=
c
.
getValueFrom
(
f
,
d
)
assert
.
NotNil
(
t
,
err
)
assert
.
Equal
(
t
,
"strconv.ParseFloat: parsing
\"
2.220000ddsf0000000002-r
\"
: invalid syntax"
,
err
.
Error
())
val
,
err
=
c
.
getValueFrom
(
f
,
d
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
"2.220000ddsf0000000002-r"
,
val
)
c
=
&
xlsxC
{
T
:
"n"
,
V
:
"2.2."
}
val
,
err
=
c
.
getValueFrom
(
f
,
d
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
"2.2."
,
val
)
}
func
TestErrSheetNotExistError
(
t
*
testing
.
T
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录