From 50980fe02e049ea4d42e8ec68af2c7269b702524 Mon Sep 17 00:00:00 2001 From: Vyacheslav Zgordan Date: Thu, 5 Dec 2019 18:16:38 +0300 Subject: [PATCH] TEXT (#354) --- spreadsheet/format/format.go | 2 +- spreadsheet/formula/fntext.go | 30 +++++++++++++++++++++++++++ spreadsheet/formula/functions_test.go | 19 +++++++++++++++-- spreadsheet/formula/result.go | 3 +++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/spreadsheet/format/format.go b/spreadsheet/format/format.go index 7ad481ea..d5e30a7f 100644 --- a/spreadsheet/format/format.go +++ b/spreadsheet/format/format.go @@ -129,7 +129,7 @@ func (f *Format) AddToken(t FmtType, l []byte) { // string is empty, then General number formatting is used which attempts to mimic // Excel's general formatting. func Number(v float64, f string) string { - if f == "" || f == "General" { + if f == "" || f == "General" || f == "@" { return NumberGeneric(v) } fmts := Parse(f) diff --git a/spreadsheet/formula/fntext.go b/spreadsheet/formula/fntext.go index 7a851ffb..ef215326 100644 --- a/spreadsheet/formula/fntext.go +++ b/spreadsheet/formula/fntext.go @@ -15,6 +15,7 @@ import ( "unicode" "github.com/unidoc/unioffice/internal/wildcard" + "github.com/unidoc/unioffice/spreadsheet/format" ) func init() { @@ -40,6 +41,7 @@ func init() { RegisterFunction("SEARCH", Search) RegisterFunctionComplex("SEARCHB", Searchb) RegisterFunction("T", T) + RegisterFunction("TEXT", Text) RegisterFunction("TEXTJOIN", TextJoin) RegisterFunction("_xlfn.TEXTJOIN", TextJoin) RegisterFunction("TRIM", Trim) @@ -721,3 +723,31 @@ func appendSlices(s0, s1 []string) []string { } return s0 } + +// Text is an implementation of the Excel TEXT function. +func Text(args []Result) Result { + if len(args) != 2 { + return MakeErrorResult("TEXT requires two arguments") + } + valueResult := args[0] + if valueResult.Type != ResultTypeNumber && valueResult.Type != ResultTypeString && valueResult.Type != ResultTypeEmpty { + return MakeErrorResult("TEXT requires first argument to be a number or string") + } + if args[1].Type != ResultTypeString { + return MakeErrorResult("TEXT requires second argument to be a string") + } + f := args[1].ValueString + + switch valueResult.Type { + case ResultTypeNumber: + return MakeStringResult(format.Number(valueResult.ValueNumber, f)) + case ResultTypeString: + return MakeStringResult(format.String(valueResult.ValueString, f)) + case ResultTypeEmpty: + return MakeStringResult(format.Number(0, f)) + case ResultTypeArray, ResultTypeList: + return MakeErrorResultType(ErrorTypeSpill, "TEXT doesn't work with arrays") + default: + return MakeErrorResult("Incorrect argument for TEXT") + } +} diff --git a/spreadsheet/formula/functions_test.go b/spreadsheet/formula/functions_test.go index bc258dd6..3c95814c 100644 --- a/spreadsheet/formula/functions_test.go +++ b/spreadsheet/formula/functions_test.go @@ -1575,7 +1575,6 @@ func TestIndex(t *testing.T) { sheet.Cell("A4").SetFormulaRaw(`=INDEX(A1:C3,1,1)`) sheet.Cell("A5").SetFormulaArray(`=INDEX(A1:C3,2)`) sheet.Cell("A6").SetFormulaArray(`=INDEX(A1:C3,,2)`) - sheet.Cell("A10").SetFormulaArray(`=INDEX(A1:C3)`) sheet.RecalculateFormulas() @@ -1586,7 +1585,23 @@ func TestIndex(t *testing.T) { {`=C5`, `6 ResultTypeNumber`}, {`=A7`, `5 ResultTypeNumber`}, {`=A8`, `8 ResultTypeNumber`}, - {`=A10`, `#VALUE! ResultTypeError`}, + } + + ctx := sheet.FormulaContext() + + runTests(t, ctx, td) +} + +func TestText(t *testing.T) { + ss := spreadsheet.New() + sheet := ss.AddSheet() + + td := []testStruct{ + {`=TEXT(A1,"0#.00")`, `00.00 ResultTypeString`}, + {`=TEXT(1,"0.00")`, `1.00 ResultTypeString`}, + {`=TEXT(12345678,"0.00E+000")`, `1.23E+007 ResultTypeString`}, + {`=TEXT(0.987654321,"0.000%")`, `98.765% ResultTypeString`}, + {`=TEXT(0.05,"# ??/??")`, `1/20 ResultTypeString`}, } ctx := sheet.FormulaContext() diff --git a/spreadsheet/formula/result.go b/spreadsheet/formula/result.go index 647712da..948642c6 100644 --- a/spreadsheet/formula/result.go +++ b/spreadsheet/formula/result.go @@ -158,6 +158,7 @@ const ( ErrorTypeRef ErrorTypeName ErrorTypeNum + ErrorTypeSpill ErrorTypeNA ErrorTypeDivideByZero ) @@ -176,6 +177,8 @@ func MakeErrorResultType(t ErrorType, msg string) Result { return Result{Type: ResultTypeError, ValueString: "#NAME?", ErrorMessage: msg} case ErrorTypeNum: return Result{Type: ResultTypeError, ValueString: "#NUM!", ErrorMessage: msg} + case ErrorTypeSpill: + return Result{Type: ResultTypeError, ValueString: "#SPILL!", ErrorMessage: msg} case ErrorTypeNA: return Result{Type: ResultTypeError, ValueString: "#N/A", ErrorMessage: msg} case ErrorTypeDivideByZero: