summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2021-12-09 20:16:12 +0800
committerxuri <xuri.me@gmail.com>2021-12-09 20:16:12 +0800
commit1b3040659d3155732961c45b0c2e13e39e0b2576 (patch)
treec5d371af1b50c79ea6b2bd4bfbeb8e4f2ea343f6
parent5bf35f8c1c18eafb2e423ae3b77868bcccc505ff (diff)
ref #65: new formula functions: ISFORMULA, ISLOGICAL and ISREF
-rw-r--r--calc.go58
-rw-r--r--calc_test.go33
2 files changed, 91 insertions, 0 deletions
diff --git a/calc.go b/calc.go
index e9ac0c8..ebfa815 100644
--- a/calc.go
+++ b/calc.go
@@ -449,10 +449,13 @@ type formulaFuncs struct {
// ISERR
// ISERROR
// ISEVEN
+// ISFORMULA
+// ISLOGICAL
// ISNA
// ISNONTEXT
// ISNUMBER
// ISODD
+// ISREF
// ISTEXT
// ISO.CEILING
// ISOWEEKNUM
@@ -6622,6 +6625,44 @@ func (fn *formulaFuncs) ISEVEN(argsList *list.List) formulaArg {
return newStringFormulaArg(result)
}
+// ISFORMULA function tests if a specified cell contains a formula, and if so,
+// returns TRUE; Otherwise, the function returns FALSE. The syntax of the
+// function is:
+//
+// ISFORMULA(reference)
+//
+func (fn *formulaFuncs) ISFORMULA(argsList *list.List) formulaArg {
+ if argsList.Len() != 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "ISFORMULA requires 1 argument")
+ }
+ arg := argsList.Front().Value.(formulaArg)
+ if arg.cellRefs != nil && arg.cellRefs.Len() == 1 {
+ ref := arg.cellRefs.Front().Value.(cellRef)
+ cell, _ := CoordinatesToCellName(ref.Col, ref.Row)
+ if formula, _ := fn.f.GetCellFormula(ref.Sheet, cell); len(formula) > 0 {
+ return newBoolFormulaArg(true)
+ }
+ }
+ return newBoolFormulaArg(false)
+}
+
+// ISLOGICAL function tests if a supplied value (or expression) returns a
+// logical value (i.e. evaluates to True or False). If so, the function
+// returns TRUE; Otherwise, it returns FALSE. The syntax of the function is:
+//
+// ISLOGICAL(value)
+//
+func (fn *formulaFuncs) ISLOGICAL(argsList *list.List) formulaArg {
+ if argsList.Len() != 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "ISLOGICAL requires 1 argument")
+ }
+ val := argsList.Front().Value.(formulaArg).Value()
+ if strings.EqualFold("TRUE", val) || strings.EqualFold("FALSE", val) {
+ return newBoolFormulaArg(true)
+ }
+ return newBoolFormulaArg(false)
+}
+
// ISNA function tests if an initial supplied expression (or value) returns
// the Excel #N/A Error, and if so, returns TRUE; Otherwise the function
// returns FALSE. The syntax of the function is:
@@ -6704,6 +6745,23 @@ func (fn *formulaFuncs) ISODD(argsList *list.List) formulaArg {
return newStringFormulaArg(result)
}
+// ISREF function tests if a supplied value is a reference. If so, the
+// function returns TRUE; Otherwise it returns FALSE. The syntax of the
+// function is:
+//
+// ISREF(value)
+//
+func (fn *formulaFuncs) ISREF(argsList *list.List) formulaArg {
+ if argsList.Len() != 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "ISREF requires 1 argument")
+ }
+ arg := argsList.Front().Value.(formulaArg)
+ if arg.cellRanges != nil && arg.cellRanges.Len() > 0 || arg.cellRefs != nil && arg.cellRefs.Len() > 0 {
+ return newBoolFormulaArg(true)
+ }
+ return newBoolFormulaArg(false)
+}
+
// ISTEXT function tests if a supplied value is text, and if so, returns TRUE;
// Otherwise, the function returns FALSE. The syntax of the function is:
//
diff --git a/calc_test.go b/calc_test.go
index 1de8fb8..50f8023 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -988,6 +988,17 @@ func TestCalcCellValue(t *testing.T) {
// ISEVEN
"=ISEVEN(A1)": "FALSE",
"=ISEVEN(A2)": "TRUE",
+ // ISFORMULA
+ "=ISFORMULA(A1)": "FALSE",
+ "=ISFORMULA(\"A\")": "FALSE",
+ // ISLOGICAL
+ "=ISLOGICAL(TRUE)": "TRUE",
+ "=ISLOGICAL(FALSE)": "TRUE",
+ "=ISLOGICAL(A1=A2)": "TRUE",
+ "=ISLOGICAL(\"true\")": "TRUE",
+ "=ISLOGICAL(\"false\")": "TRUE",
+ "=ISLOGICAL(A1)": "FALSE",
+ "=ISLOGICAL(20/5)": "FALSE",
// ISNA
"=ISNA(A1)": "FALSE",
"=ISNA(NA())": "TRUE",
@@ -1002,6 +1013,11 @@ func TestCalcCellValue(t *testing.T) {
// ISODD
"=ISODD(A1)": "TRUE",
"=ISODD(A2)": "FALSE",
+ // ISREF
+ "=ISREF(B1)": "TRUE",
+ "=ISREF(B1:B2)": "TRUE",
+ "=ISREF(\"text\")": "FALSE",
+ "=ISREF(B1*B2)": "FALSE",
// ISTEXT
"=ISTEXT(D1)": "TRUE",
"=ISTEXT(A1)": "FALSE",
@@ -2402,6 +2418,10 @@ func TestCalcCellValue(t *testing.T) {
// ISEVEN
"=ISEVEN()": "ISEVEN requires 1 argument",
`=ISEVEN("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
+ // ISFORMULA
+ "=ISFORMULA()": "ISFORMULA requires 1 argument",
+ // ISLOGICAL
+ "=ISLOGICAL()": "ISLOGICAL requires 1 argument",
// ISNA
"=ISNA()": "ISNA requires 1 argument",
// ISNONTEXT
@@ -2411,6 +2431,8 @@ func TestCalcCellValue(t *testing.T) {
// ISODD
"=ISODD()": "ISODD requires 1 argument",
`=ISODD("text")`: "strconv.Atoi: parsing \"text\": invalid syntax",
+ // ISREF
+ "=ISREF()": "ISREF requires 1 argument",
// ISTEXT
"=ISTEXT()": "ISTEXT requires 1 argument",
// N
@@ -3725,6 +3747,17 @@ func TestCalcMATCH(t *testing.T) {
assert.Equal(t, newErrorFormulaArg(formulaErrorNA, formulaErrorNA), calcMatch(2, nil, []formulaArg{}))
}
+func TestCalcISFORMULA(t *testing.T) {
+ f := NewFile()
+ assert.NoError(t, f.SetCellFormula("Sheet1", "B1", "=ISFORMULA(A1)"))
+ for _, formula := range []string{"=NA()", "=SUM(A1:A3)"} {
+ assert.NoError(t, f.SetCellFormula("Sheet1", "A1", formula))
+ result, err := f.CalcCellValue("Sheet1", "B1")
+ assert.NoError(t, err, formula)
+ assert.Equal(t, "TRUE", result, formula)
+ }
+}
+
func TestCalcZTEST(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetSheetRow("Sheet1", "A1", &[]int{4, 5, 2, 5, 8, 9, 3, 2, 3, 8, 9, 5}))