forked from p30928647/excelize
This closes #785, support to change tab color; new formula function: FISHER, FISHERINV, GAMMA, GAMMALN, MIN, MINA, PERMUT
This commit is contained in:
parent
36b7990d6b
commit
bddea1262b
278
calc.go
278
calc.go
|
@ -249,9 +249,13 @@ var tokenPriority = map[string]int{
|
|||
// FACT
|
||||
// FACTDOUBLE
|
||||
// FALSE
|
||||
// FISHER
|
||||
// FISHERINV
|
||||
// FLOOR
|
||||
// FLOOR.MATH
|
||||
// FLOOR.PRECISE
|
||||
// GAMMA
|
||||
// GAMMALN
|
||||
// GCD
|
||||
// HLOOKUP
|
||||
// IF
|
||||
|
@ -278,6 +282,8 @@ var tokenPriority = map[string]int{
|
|||
// MAX
|
||||
// MDETERM
|
||||
// MEDIAN
|
||||
// MIN
|
||||
// MINA
|
||||
// MOD
|
||||
// MROUND
|
||||
// MULTINOMIAL
|
||||
|
@ -286,6 +292,7 @@ var tokenPriority = map[string]int{
|
|||
// NOT
|
||||
// ODD
|
||||
// OR
|
||||
// PERMUT
|
||||
// PI
|
||||
// POWER
|
||||
// PRODUCT
|
||||
|
@ -295,6 +302,7 @@ var tokenPriority = map[string]int{
|
|||
// RAND
|
||||
// RANDBETWEEN
|
||||
// REPT
|
||||
// ROMAN
|
||||
// ROUND
|
||||
// ROUNDDOWN
|
||||
// ROUNDUP
|
||||
|
@ -1798,7 +1806,7 @@ func (fn *formulaFuncs) FACT(argsList *list.List) formulaArg {
|
|||
if number.Number < 0 {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
return newStringFormulaArg(strings.ToUpper(fmt.Sprintf("%g", fact(number.Number))))
|
||||
return newNumberFormulaArg(fact(number.Number))
|
||||
}
|
||||
|
||||
// FACTDOUBLE function returns the double factorial of a supplied number. The
|
||||
|
@ -2552,7 +2560,8 @@ func (fn *formulaFuncs) RANDBETWEEN(argsList *list.List) formulaArg {
|
|||
if top.Number < bottom.Number {
|
||||
return newErrorFormulaArg(formulaErrorNUM, formulaErrorNUM)
|
||||
}
|
||||
return newNumberFormulaArg(float64(rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number-bottom.Number+1)) + int64(bottom.Number)))
|
||||
num := rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(int64(top.Number - bottom.Number + 1))
|
||||
return newNumberFormulaArg(float64(num + int64(bottom.Number)))
|
||||
}
|
||||
|
||||
// romanNumerals defined a numeral system that originated in ancient Rome and
|
||||
|
@ -2563,11 +2572,34 @@ type romanNumerals struct {
|
|||
s string
|
||||
}
|
||||
|
||||
var romanTable = [][]romanNumerals{{{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
|
||||
{{1000, "M"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {95, "VC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
|
||||
{{1000, "M"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
|
||||
{{1000, "M"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}},
|
||||
{{1000, "M"}, {999, "IM"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {499, "ID"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}}}
|
||||
var romanTable = [][]romanNumerals{
|
||||
{
|
||||
{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"},
|
||||
{50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
|
||||
},
|
||||
{
|
||||
{1000, "M"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {450, "LD"}, {400, "CD"},
|
||||
{100, "C"}, {95, "VC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"},
|
||||
{10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
|
||||
},
|
||||
{
|
||||
{1000, "M"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"}, {490, "XD"},
|
||||
{450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"},
|
||||
{45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
|
||||
},
|
||||
{
|
||||
{1000, "M"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"}, {500, "D"},
|
||||
{495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"}, {100, "C"}, {99, "IC"},
|
||||
{90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"}, {10, "X"}, {9, "IX"},
|
||||
{5, "V"}, {4, "IV"}, {1, "I"},
|
||||
},
|
||||
{
|
||||
{1000, "M"}, {999, "IM"}, {995, "VM"}, {990, "XM"}, {950, "LM"}, {900, "CM"},
|
||||
{500, "D"}, {499, "ID"}, {495, "VD"}, {490, "XD"}, {450, "LD"}, {400, "CD"},
|
||||
{100, "C"}, {99, "IC"}, {90, "XC"}, {50, "L"}, {45, "VL"}, {40, "XL"},
|
||||
{10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"},
|
||||
},
|
||||
}
|
||||
|
||||
// ROMAN function converts an arabic number to Roman. I.e. for a supplied
|
||||
// integer, the function returns a text string depicting the roman numeral
|
||||
|
@ -3191,6 +3223,112 @@ func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg {
|
|||
return newNumberFormulaArg(float64(count))
|
||||
}
|
||||
|
||||
// FISHER function calculates the Fisher Transformation for a supplied value.
|
||||
// The syntax of the function is:
|
||||
//
|
||||
// FISHER(x)
|
||||
//
|
||||
func (fn *formulaFuncs) FISHER(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 1 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument")
|
||||
}
|
||||
token := argsList.Front().Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgString:
|
||||
arg := token.ToNumber()
|
||||
if arg.Type == ArgNumber {
|
||||
if arg.Number <= -1 || arg.Number >= 1 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(0.5 * math.Log((1+arg.Number)/(1-arg.Number)))
|
||||
}
|
||||
case ArgNumber:
|
||||
if token.Number <= -1 || token.Number >= 1 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(0.5 * math.Log((1+token.Number)/(1-token.Number)))
|
||||
}
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "FISHER requires 1 numeric argument")
|
||||
}
|
||||
|
||||
// FISHERINV function calculates the inverse of the Fisher Transformation and
|
||||
// returns a value between -1 and +1. The syntax of the function is:
|
||||
//
|
||||
// FISHERINV(y)
|
||||
//
|
||||
func (fn *formulaFuncs) FISHERINV(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 1 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument")
|
||||
}
|
||||
token := argsList.Front().Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgString:
|
||||
arg := token.ToNumber()
|
||||
if arg.Type == ArgNumber {
|
||||
return newNumberFormulaArg((math.Exp(2*arg.Number) - 1) / (math.Exp(2*arg.Number) + 1))
|
||||
}
|
||||
case ArgNumber:
|
||||
return newNumberFormulaArg((math.Exp(2*token.Number) - 1) / (math.Exp(2*token.Number) + 1))
|
||||
}
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "FISHERINV requires 1 numeric argument")
|
||||
}
|
||||
|
||||
// GAMMA function returns the value of the Gamma Function, Γ(n), for a
|
||||
// specified number, n. The syntax of the function is:
|
||||
//
|
||||
// GAMMA(number)
|
||||
//
|
||||
func (fn *formulaFuncs) GAMMA(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 1 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument")
|
||||
}
|
||||
token := argsList.Front().Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgString:
|
||||
arg := token.ToNumber()
|
||||
if arg.Type == ArgNumber {
|
||||
if arg.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(math.Gamma(arg.Number))
|
||||
}
|
||||
case ArgNumber:
|
||||
if token.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(math.Gamma(token.Number))
|
||||
}
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "GAMMA requires 1 numeric argument")
|
||||
}
|
||||
|
||||
// GAMMALN function returns the natural logarithm of the Gamma Function, Γ
|
||||
// (n). The syntax of the function is:
|
||||
//
|
||||
// GAMMALN(x)
|
||||
//
|
||||
func (fn *formulaFuncs) GAMMALN(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 1 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument")
|
||||
}
|
||||
token := argsList.Front().Value.(formulaArg)
|
||||
switch token.Type {
|
||||
case ArgString:
|
||||
arg := token.ToNumber()
|
||||
if arg.Type == ArgNumber {
|
||||
if arg.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(math.Log(math.Gamma(arg.Number)))
|
||||
}
|
||||
case ArgNumber:
|
||||
if token.Number <= 0 {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(math.Log(math.Gamma(token.Number)))
|
||||
}
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "GAMMALN requires 1 numeric argument")
|
||||
}
|
||||
|
||||
// MAX function returns the largest value from a supplied set of numeric
|
||||
// values. The syntax of the function is:
|
||||
//
|
||||
|
@ -3203,7 +3341,10 @@ func (fn *formulaFuncs) MAX(argsList *list.List) formulaArg {
|
|||
return fn.max(false, argsList)
|
||||
}
|
||||
|
||||
// MAXA function returns the largest value from a supplied set of numeric values, while counting text and the logical value FALSE as the value 0 and counting the logical value TRUE as the value 1. The syntax of the function is:
|
||||
// MAXA function returns the largest value from a supplied set of numeric
|
||||
// values, while counting text and the logical value FALSE as the value 0 and
|
||||
// counting the logical value TRUE as the value 1. The syntax of the function
|
||||
// is:
|
||||
//
|
||||
// MAXA(number1,[number2],...)
|
||||
//
|
||||
|
@ -3317,6 +3458,112 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
|
|||
return newNumberFormulaArg(median)
|
||||
}
|
||||
|
||||
// MIN function returns the smallest value from a supplied set of numeric
|
||||
// values. The syntax of the function is:
|
||||
//
|
||||
// MIN(number1,[number2],...)
|
||||
//
|
||||
func (fn *formulaFuncs) MIN(argsList *list.List) formulaArg {
|
||||
if argsList.Len() == 0 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "MIN requires at least 1 argument")
|
||||
}
|
||||
return fn.min(false, argsList)
|
||||
}
|
||||
|
||||
// MINA function returns the smallest value from a supplied set of numeric
|
||||
// values, while counting text and the logical value FALSE as the value 0 and
|
||||
// counting the logical value TRUE as the value 1. The syntax of the function
|
||||
// is:
|
||||
//
|
||||
// MINA(number1,[number2],...)
|
||||
//
|
||||
func (fn *formulaFuncs) MINA(argsList *list.List) formulaArg {
|
||||
if argsList.Len() == 0 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "MINA requires at least 1 argument")
|
||||
}
|
||||
return fn.min(true, argsList)
|
||||
}
|
||||
|
||||
// min is an implementation of the formula function MIN and MINA.
|
||||
func (fn *formulaFuncs) min(mina bool, argsList *list.List) formulaArg {
|
||||
min := math.MaxFloat64
|
||||
for token := argsList.Front(); token != nil; token = token.Next() {
|
||||
arg := token.Value.(formulaArg)
|
||||
switch arg.Type {
|
||||
case ArgString:
|
||||
if !mina && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
|
||||
continue
|
||||
} else {
|
||||
num := arg.ToBool()
|
||||
if num.Type == ArgNumber && num.Number < min {
|
||||
min = num.Number
|
||||
continue
|
||||
}
|
||||
}
|
||||
num := arg.ToNumber()
|
||||
if num.Type != ArgError && num.Number < min {
|
||||
min = num.Number
|
||||
}
|
||||
case ArgNumber:
|
||||
if arg.Number < min {
|
||||
min = arg.Number
|
||||
}
|
||||
case ArgList, ArgMatrix:
|
||||
for _, row := range arg.ToList() {
|
||||
switch row.Type {
|
||||
case ArgString:
|
||||
if !mina && (row.Value() == "TRUE" || row.Value() == "FALSE") {
|
||||
continue
|
||||
} else {
|
||||
num := row.ToBool()
|
||||
if num.Type == ArgNumber && num.Number < min {
|
||||
min = num.Number
|
||||
continue
|
||||
}
|
||||
}
|
||||
num := row.ToNumber()
|
||||
if num.Type != ArgError && num.Number < min {
|
||||
min = num.Number
|
||||
}
|
||||
case ArgNumber:
|
||||
if row.Number < min {
|
||||
min = row.Number
|
||||
}
|
||||
}
|
||||
}
|
||||
case ArgError:
|
||||
return arg
|
||||
}
|
||||
}
|
||||
if min == math.MaxFloat64 {
|
||||
min = 0
|
||||
}
|
||||
return newNumberFormulaArg(min)
|
||||
}
|
||||
|
||||
// PERMUT function calculates the number of permutations of a specified number
|
||||
// of objects from a set of objects. The syntax of the function is:
|
||||
//
|
||||
// PERMUT(number,number_chosen)
|
||||
//
|
||||
func (fn *formulaFuncs) PERMUT(argsList *list.List) formulaArg {
|
||||
if argsList.Len() != 2 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "PERMUT requires 2 numeric arguments")
|
||||
}
|
||||
number := argsList.Front().Value.(formulaArg).ToNumber()
|
||||
chosen := argsList.Back().Value.(formulaArg).ToNumber()
|
||||
if number.Type != ArgNumber {
|
||||
return number
|
||||
}
|
||||
if chosen.Type != ArgNumber {
|
||||
return chosen
|
||||
}
|
||||
if number.Number < chosen.Number {
|
||||
return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
|
||||
}
|
||||
return newNumberFormulaArg(math.Round(fact(number.Number) / fact(number.Number-chosen.Number)))
|
||||
}
|
||||
|
||||
// Information Functions
|
||||
|
||||
// ISBLANK function tests if a specified cell is blank (empty) and if so,
|
||||
|
@ -3356,7 +3603,11 @@ func (fn *formulaFuncs) ISERR(argsList *list.List) formulaArg {
|
|||
token := argsList.Front().Value.(formulaArg)
|
||||
result := "FALSE"
|
||||
if token.Type == ArgError {
|
||||
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
|
||||
for _, errType := range []string{
|
||||
formulaErrorDIV, formulaErrorNAME, formulaErrorNUM,
|
||||
formulaErrorVALUE, formulaErrorREF, formulaErrorNULL,
|
||||
formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA,
|
||||
} {
|
||||
if errType == token.String {
|
||||
result = "TRUE"
|
||||
}
|
||||
|
@ -3378,7 +3629,11 @@ func (fn *formulaFuncs) ISERROR(argsList *list.List) formulaArg {
|
|||
token := argsList.Front().Value.(formulaArg)
|
||||
result := "FALSE"
|
||||
if token.Type == ArgError {
|
||||
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
|
||||
for _, errType := range []string{
|
||||
formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM,
|
||||
formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL,
|
||||
formulaErrorCALC, formulaErrorGETTINGDATA,
|
||||
} {
|
||||
if errType == token.String {
|
||||
result = "TRUE"
|
||||
}
|
||||
|
@ -4413,5 +4668,6 @@ func (fn *formulaFuncs) ENCODEURL(argsList *list.List) formulaArg {
|
|||
if argsList.Len() != 1 {
|
||||
return newErrorFormulaArg(formulaErrorVALUE, "ENCODEURL requires 1 argument")
|
||||
}
|
||||
return newStringFormulaArg(strings.Replace(url.QueryEscape(argsList.Front().Value.(formulaArg).Value()), "+", "%20", -1))
|
||||
token := argsList.Front().Value.(formulaArg).Value()
|
||||
return newStringFormulaArg(strings.Replace(url.QueryEscape(token), "+", "%20", -1))
|
||||
}
|
||||
|
|
83
calc_test.go
83
calc_test.go
|
@ -205,7 +205,7 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// FACT
|
||||
"=FACT(3)": "6",
|
||||
"=FACT(6)": "720",
|
||||
"=FACT(10)": "3.6288E+06",
|
||||
"=FACT(10)": "3.6288e+06",
|
||||
"=FACT(FACT(3))": "720",
|
||||
// FACTDOUBLE
|
||||
"=FACTDOUBLE(5)": "15",
|
||||
|
@ -490,6 +490,23 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=COUNTBLANK(1)": "0",
|
||||
"=COUNTBLANK(B1:C1)": "1",
|
||||
"=COUNTBLANK(C1)": "1",
|
||||
// FISHER
|
||||
"=FISHER(-0.9)": "-1.47221948958322",
|
||||
"=FISHER(-0.25)": "-0.255412811882995",
|
||||
"=FISHER(0.8)": "1.09861228866811",
|
||||
"=FISHER(INT(0))": "0",
|
||||
// FISHERINV
|
||||
"=FISHERINV(-0.2)": "-0.197375320224904",
|
||||
"=FISHERINV(INT(0))": "0",
|
||||
"=FISHERINV(2.8)": "0.992631520201128",
|
||||
// GAMMA
|
||||
"=GAMMA(0.1)": "9.513507698668732",
|
||||
"=GAMMA(INT(1))": "1",
|
||||
"=GAMMA(1.5)": "0.886226925452758",
|
||||
"=GAMMA(5.5)": "52.34277778455352",
|
||||
// GAMMALN
|
||||
"=GAMMALN(4.5)": "2.453736570842443",
|
||||
"=GAMMALN(INT(1))": "0",
|
||||
// MAX
|
||||
"=MAX(1)": "1",
|
||||
"=MAX(TRUE())": "1",
|
||||
|
@ -509,6 +526,25 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=MEDIAN(A1:A5,12)": "2",
|
||||
"=MEDIAN(A1:A5)": "1.5",
|
||||
"=MEDIAN(A1:A5,MEDIAN(A1:A5,12))": "2",
|
||||
// MIN
|
||||
"=MIN(1)": "1",
|
||||
"=MIN(TRUE())": "1",
|
||||
"=MIN(0.5,FALSE())": "0",
|
||||
"=MIN(FALSE())": "0",
|
||||
"=MIN(MUNIT(2))": "0",
|
||||
"=MIN(INT(1))": "1",
|
||||
// MINA
|
||||
"=MINA(1)": "1",
|
||||
"=MINA(TRUE())": "1",
|
||||
"=MINA(0.5,FALSE())": "0",
|
||||
"=MINA(FALSE())": "0",
|
||||
"=MINA(MUNIT(2))": "0",
|
||||
"=MINA(INT(1))": "1",
|
||||
"=MINA(A1:B4,MUNIT(1),INT(0),1,E1:F2,\"\")": "0",
|
||||
// PERMUT
|
||||
"=PERMUT(6,6)": "720",
|
||||
"=PERMUT(7,6)": "5040",
|
||||
"=PERMUT(10,6)": "151200",
|
||||
// Information Functions
|
||||
// ISBLANK
|
||||
"=ISBLANK(A1)": "FALSE",
|
||||
|
@ -940,6 +976,24 @@ func TestCalcCellValue(t *testing.T) {
|
|||
// COUNTBLANK
|
||||
"=COUNTBLANK()": "COUNTBLANK requires 1 argument",
|
||||
"=COUNTBLANK(1,2)": "COUNTBLANK requires 1 argument",
|
||||
// FISHER
|
||||
"=FISHER()": "FISHER requires 1 numeric argument",
|
||||
"=FISHER(2)": "#N/A",
|
||||
"=FISHER(INT(-2)))": "#N/A",
|
||||
"=FISHER(F1)": "FISHER requires 1 numeric argument",
|
||||
// FISHERINV
|
||||
"=FISHERINV()": "FISHERINV requires 1 numeric argument",
|
||||
"=FISHERINV(F1)": "FISHERINV requires 1 numeric argument",
|
||||
// GAMMA
|
||||
"=GAMMA()": "GAMMA requires 1 numeric argument",
|
||||
"=GAMMA(F1)": "GAMMA requires 1 numeric argument",
|
||||
"=GAMMA(0)": "#N/A",
|
||||
"=GAMMA(INT(0))": "#N/A",
|
||||
// GAMMALN
|
||||
"=GAMMALN()": "GAMMALN requires 1 numeric argument",
|
||||
"=GAMMALN(F1)": "GAMMALN requires 1 numeric argument",
|
||||
"=GAMMALN(0)": "#N/A",
|
||||
"=GAMMALN(INT(0))": "#N/A",
|
||||
// MAX
|
||||
"=MAX()": "MAX requires at least 1 argument",
|
||||
"=MAX(NA())": "#N/A",
|
||||
|
@ -950,6 +1004,17 @@ func TestCalcCellValue(t *testing.T) {
|
|||
"=MEDIAN()": "MEDIAN requires at least 1 argument",
|
||||
"=MEDIAN(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=MEDIAN(D1:D2)": "strconv.ParseFloat: parsing \"Month\": invalid syntax",
|
||||
// MIN
|
||||
"=MIN()": "MIN requires at least 1 argument",
|
||||
"=MIN(NA())": "#N/A",
|
||||
// MINA
|
||||
"=MINA()": "MINA requires at least 1 argument",
|
||||
"=MINA(NA())": "#N/A",
|
||||
// PERMUT
|
||||
"=PERMUT()": "PERMUT requires 2 numeric arguments",
|
||||
"=PERMUT(\"\",0)": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PERMUT(0,\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
|
||||
"=PERMUT(6,8)": "#N/A",
|
||||
// Information Functions
|
||||
// ISBLANK
|
||||
"=ISBLANK(A1,A2)": "ISBLANK requires 1 argument",
|
||||
|
@ -1315,16 +1380,20 @@ func TestCalcVLOOKUP(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCalcMAX(t *testing.T) {
|
||||
func TestCalcMAXMIN(t *testing.T) {
|
||||
cellData := [][]interface{}{
|
||||
{0.5, "TRUE"},
|
||||
{0.5, "TRUE", -0.5, "FALSE"},
|
||||
}
|
||||
f := prepareCalcData(cellData)
|
||||
formulaList := map[string]string{
|
||||
"=MAX(0.5,B1)": "0.5",
|
||||
"=MAX(A1:B1)": "0.5",
|
||||
"=MAXA(A1:B1)": "1",
|
||||
"=MAXA(0.5,B1)": "1",
|
||||
"=MAX(0.5,B1)": "0.5",
|
||||
"=MAX(A1:B1)": "0.5",
|
||||
"=MAXA(A1:B1)": "1",
|
||||
"=MAXA(0.5,B1)": "1",
|
||||
"=MIN(-0.5,D1)": "-0.5",
|
||||
"=MIN(C1:D1)": "-0.5",
|
||||
"=MINA(C1:D1)": "-0.5",
|
||||
"=MINA(-0.5,D1)": "-0.5",
|
||||
}
|
||||
for formula, expected := range formulaList {
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "B10", formula))
|
||||
|
|
|
@ -939,7 +939,8 @@ func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls {
|
|||
// given format sets.
|
||||
func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls {
|
||||
dLbls := f.drawChartDLbls(formatSet)
|
||||
chartSeriesDLbls := map[string]*cDLbls{Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil}
|
||||
chartSeriesDLbls := map[string]*cDLbls{
|
||||
Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil}
|
||||
if _, ok := chartSeriesDLbls[formatSet.Type]; ok {
|
||||
return nil
|
||||
}
|
||||
|
|
26
sheetpr.go
26
sheetpr.go
|
@ -11,6 +11,8 @@
|
|||
|
||||
package excelize
|
||||
|
||||
import "strings"
|
||||
|
||||
// SheetPrOption is an option of a view of a worksheet. See SetSheetPrOptions().
|
||||
type SheetPrOption interface {
|
||||
setSheetPrOption(view *xlsxSheetPr)
|
||||
|
@ -31,6 +33,8 @@ type (
|
|||
Published bool
|
||||
// FitToPage is a SheetPrOption
|
||||
FitToPage bool
|
||||
// TabColor is a SheetPrOption
|
||||
TabColor string
|
||||
// AutoPageBreaks is a SheetPrOption
|
||||
AutoPageBreaks bool
|
||||
// OutlineSummaryBelow is an outlinePr, within SheetPr option
|
||||
|
@ -125,6 +129,28 @@ func (o *FitToPage) getSheetPrOption(pr *xlsxSheetPr) {
|
|||
*o = FitToPage(pr.PageSetUpPr.FitToPage)
|
||||
}
|
||||
|
||||
// setSheetPrOption implements the SheetPrOption interface and specifies a
|
||||
// stable name of the sheet.
|
||||
func (o TabColor) setSheetPrOption(pr *xlsxSheetPr) {
|
||||
if pr.TabColor == nil {
|
||||
if string(o) == "" {
|
||||
return
|
||||
}
|
||||
pr.TabColor = new(xlsxTabColor)
|
||||
}
|
||||
pr.TabColor.RGB = getPaletteColor(string(o))
|
||||
}
|
||||
|
||||
// getSheetPrOption implements the SheetPrOptionPtr interface and get the
|
||||
// stable name of the sheet.
|
||||
func (o *TabColor) getSheetPrOption(pr *xlsxSheetPr) {
|
||||
if pr == nil || pr.TabColor == nil {
|
||||
*o = ""
|
||||
return
|
||||
}
|
||||
*o = TabColor(strings.TrimPrefix(pr.TabColor.RGB, "FF"))
|
||||
}
|
||||
|
||||
// setSheetPrOption implements the SheetPrOption interface.
|
||||
func (o AutoPageBreaks) setSheetPrOption(pr *xlsxSheetPr) {
|
||||
if pr.PageSetUpPr == nil {
|
||||
|
|
|
@ -13,6 +13,7 @@ var _ = []SheetPrOption{
|
|||
EnableFormatConditionsCalculation(false),
|
||||
Published(false),
|
||||
FitToPage(true),
|
||||
TabColor("#FFFF00"),
|
||||
AutoPageBreaks(true),
|
||||
OutlineSummaryBelow(true),
|
||||
}
|
||||
|
@ -22,6 +23,7 @@ var _ = []SheetPrOptionPtr{
|
|||
(*EnableFormatConditionsCalculation)(nil),
|
||||
(*Published)(nil),
|
||||
(*FitToPage)(nil),
|
||||
(*TabColor)(nil),
|
||||
(*AutoPageBreaks)(nil),
|
||||
(*OutlineSummaryBelow)(nil),
|
||||
}
|
||||
|
@ -35,6 +37,7 @@ func ExampleFile_SetSheetPrOptions() {
|
|||
EnableFormatConditionsCalculation(false),
|
||||
Published(false),
|
||||
FitToPage(true),
|
||||
TabColor("#FFFF00"),
|
||||
AutoPageBreaks(true),
|
||||
OutlineSummaryBelow(false),
|
||||
); err != nil {
|
||||
|
@ -52,6 +55,7 @@ func ExampleFile_GetSheetPrOptions() {
|
|||
enableFormatConditionsCalculation EnableFormatConditionsCalculation
|
||||
published Published
|
||||
fitToPage FitToPage
|
||||
tabColor TabColor
|
||||
autoPageBreaks AutoPageBreaks
|
||||
outlineSummaryBelow OutlineSummaryBelow
|
||||
)
|
||||
|
@ -61,6 +65,7 @@ func ExampleFile_GetSheetPrOptions() {
|
|||
&enableFormatConditionsCalculation,
|
||||
&published,
|
||||
&fitToPage,
|
||||
&tabColor,
|
||||
&autoPageBreaks,
|
||||
&outlineSummaryBelow,
|
||||
); err != nil {
|
||||
|
@ -71,6 +76,7 @@ func ExampleFile_GetSheetPrOptions() {
|
|||
fmt.Println("- enableFormatConditionsCalculation:", enableFormatConditionsCalculation)
|
||||
fmt.Println("- published:", published)
|
||||
fmt.Println("- fitToPage:", fitToPage)
|
||||
fmt.Printf("- tabColor: %q\n", tabColor)
|
||||
fmt.Println("- autoPageBreaks:", autoPageBreaks)
|
||||
fmt.Println("- outlineSummaryBelow:", outlineSummaryBelow)
|
||||
// Output:
|
||||
|
@ -79,6 +85,7 @@ func ExampleFile_GetSheetPrOptions() {
|
|||
// - enableFormatConditionsCalculation: true
|
||||
// - published: true
|
||||
// - fitToPage: false
|
||||
// - tabColor: ""
|
||||
// - autoPageBreaks: false
|
||||
// - outlineSummaryBelow: true
|
||||
}
|
||||
|
@ -94,6 +101,7 @@ func TestSheetPrOptions(t *testing.T) {
|
|||
{new(EnableFormatConditionsCalculation), EnableFormatConditionsCalculation(false)},
|
||||
{new(Published), Published(false)},
|
||||
{new(FitToPage), FitToPage(true)},
|
||||
{new(TabColor), TabColor("FFFF00")},
|
||||
{new(AutoPageBreaks), AutoPageBreaks(true)},
|
||||
{new(OutlineSummaryBelow), OutlineSummaryBelow(false)},
|
||||
}
|
||||
|
@ -147,6 +155,7 @@ func TestSheetPrOptions(t *testing.T) {
|
|||
|
||||
func TestSetSheetrOptions(t *testing.T) {
|
||||
f := NewFile()
|
||||
assert.NoError(t, f.SetSheetPrOptions("Sheet1", TabColor("")))
|
||||
// Test SetSheetrOptions on not exists worksheet.
|
||||
assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue