summaryrefslogtreecommitdiff
path: root/formattedValue.go
diff options
context:
space:
mode:
Diffstat (limited to 'formattedValue.go')
-rw-r--r--formattedValue.go257
1 files changed, 257 insertions, 0 deletions
diff --git a/formattedValue.go b/formattedValue.go
new file mode 100644
index 0000000..e59a8df
--- /dev/null
+++ b/formattedValue.go
@@ -0,0 +1,257 @@
+package anyxcelize
+
+import (
+ "strings"
+ "strconv"
+ "math"
+ "fmt"
+)
+
+func (f *File) formattedValueGeneric(s int, v string, raw bool) (any, error) {
+ // fmt.Println("---")
+
+ if raw { fmt.Println("fvg: raw"); return v, nil }
+ // s is the style reference
+ if s == 0 { fmt.Println("fvg: s==0"); return v, nil }
+
+ styleSheet, err := f.stylesReader()
+ if err != nil {
+ fmt.Println("fvg: styleSheet err")
+ return v, err
+ }
+ if styleSheet.CellXfs == nil {
+ fmt.Println("fvg: CellXfs nil")
+ return v, err
+ }
+
+ // TODO: what does this mean?
+ if s >= len(styleSheet.CellXfs.Xf) {
+ // fmt.Println("fvg: s >= len(...Xf)")
+ return v, err
+ }
+
+ var numFmtID int
+ if styleSheet.CellXfs.Xf[s].NumFmtID != nil {
+ numFmtID = *styleSheet.CellXfs.Xf[s].NumFmtID
+ }
+ // Use this!
+ // fmt.Printf("xf[s].NumFmtID = %v\n", numFmtID)
+
+ date1904 := false
+ wb, err := f.workbookReader()
+ if err != nil {
+ // fmt.Println("fvg: wb err")
+ return v, err
+ }
+ if wb != nil && wb.WorkbookPr != nil {
+ date1904 = wb.WorkbookPr.Date1904
+ }
+ // NOTE: we get the formatting fn in ok, and
+ // call it with v, the numFmt, and date1904.
+ // We need to modify the functions that are
+ // possible to be ok, then, to return any.
+ // Only has up to ~60, so won't call on 167 (date), 164, 166 we have.
+ if ok := builtInNumFmtFuncGen[numFmtID]; ok != nil {
+ // fmt.Println("fvg: ok := ...")
+ // ok() is now a func(v, format string, date1904 bool) any !!
+ return ok(v, builtInNumFmt[numFmtID], date1904), err
+ }
+
+ // This is what actually gets called, most of the time.
+ // This means NumFmts are NOT nil, so they exist, so
+ // does this mean we can do simple ParseFloat?
+ if styleSheet.NumFmts != nil {
+ // fmt.Printf("fvg: NumFmts != nil on (%s)\n", v)
+ // return v, err
+ }
+
+ // If the above fails, we want this to work and return a correct
+ // value.
+ for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
+ if xlsxFmt.NumFmtID == numFmtID {
+ // fmt.Printf("Matched on numFmtID %v; date1904 %v format code %v\n", numFmtID, date1904, xlsxFmt.FormatCode)
+ return formatGeneric(v, xlsxFmt.FormatCode, date1904), err
+ }
+ }
+
+ return v, err
+}
+
+// builtInNumFmtFunc defined the format conversion functions map. Partial format
+// code doesn't support currently and will return original string.
+var builtInNumFmtFuncGen = map[int]func(v, format string, date1904 bool) any{
+ 0: formatGeneric,
+ 1: formatToIntGeneric, // noted; yet to implement
+ 2: formatToFloatGeneric,// noted; yet to implement
+ 3: formatToIntSeparatorGeneric,// noted; yet to implement
+ 4: formatToFloatGeneric,// noted; yet to implement
+ 9: formatToCGeneric,
+ 10: formatToDGeneric,
+ 11: formatToEGeneric,
+ 12: formatGeneric, // Doesn't support currently
+ 13: formatGeneric, // Doesn't support currently
+ 14: formatGeneric,
+ 15: formatGeneric,
+ 16: formatGeneric,
+ 17: formatGeneric,
+ 18: formatGeneric,
+ 19: formatGeneric,
+ 20: formatGeneric,
+ 21: formatGeneric,
+ 22: formatGeneric,
+ 37: formatToAGeneric,
+ 38: formatToAGeneric,
+ 39: formatToBGeneric,
+ 40: formatToBGeneric,
+ 41: formatGeneric, // Doesn't support currently
+ 42: formatGeneric, // Doesn't support currently
+ 43: formatGeneric, // Doesn't support currently
+ 44: formatGeneric, // Doesn't support currently
+ 45: formatGeneric,
+ 46: formatGeneric,
+ 47: formatGeneric,
+ 48: formatToEGeneric,
+ 49: formatGeneric,
+}
+
+// OnesGeneric to worry about implementing:
+// formatToint, formatToFloat, formatToIntSeparator, formatTo{A,B,C,D,E}
+
+// Return any or int?
+func formatToIntGeneric(v, format string, date1904 bool) any {
+ // Copied from original. Not sure what this does, probably don't want
+ // this to be the case. TODO: FIX
+ if strings.Contains(v, "_") {
+ magicerr := -420691111
+ fmt.Printf("formatToIntGeneric: v %v, format %v, date1904 %v: error %v\n", v, format, date1904, magicerr)
+ return magicerr
+ }
+
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ magicerr := -420691112
+ fmt.Printf("formatToIntGeneric: v %v, format %v, date1904 %v: error %v\n", v, format, date1904, magicerr)
+ return magicerr
+ } // ERROR!
+ return math.Round(f)
+ // That should do us!
+}
+
+
+func formatToFloatGeneric(v, format string, date1904 bool) any {
+ if strings.Contains(v, "_") { return v }
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ magicerr := -420691113
+ fmt.Printf("formatToFloatGeneric: v %v, format %v, date1904 %v: error %v\n", v, format, date1904, magicerr)
+ return magicerr
+ }
+ return f
+}
+
+func formatToIntSeparatorGeneric(v, format string, date1904 bool) any {
+ if strings.Contains(v, "_") {
+ magicerr := -420691114
+ fmt.Printf("formatToIntSeparatorGeneric: v %v, format %v, date1904 %v: error %v\n", v, format, date1904, magicerr)
+ return magicerr
+ }
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ magicerr := -420691115
+ fmt.Printf("formatToIntSeparatorGeneric: v %v, format %v, date1904 %v: error %v\n", v, format, date1904, magicerr)
+ return magicerr
+ }
+ return math.Round(f)
+}
+
+// Normally this would format as (100), 100 for -100, 100. This just returns
+// an int here
+func formatToAGeneric(v, format string, date1904 bool) any{
+ return formatToIntGeneric(v, format, date1904)
+}
+
+// The float equivalent of formatToA. Here just format as float!
+func formatToBGeneric(v, format string, date1904 bool) any {
+ return formatToFloatGeneric(v, format, date1904)
+}
+
+// Normally formats as percent. For now just keep it as is, AIEL pcts should
+// be in 10.00 format anyways not 10%. If it is, eh. For now, just format as
+// float, possibly better choices exist.
+func formatToCGeneric(v, format string, date1904 bool) any {
+ return formatToFloatGeneric(v, format, date1904)
+}
+
+// percents with 00.00% not 00%. Same as above, just do floats
+func formatToDGeneric(v, format string, date1904 bool) any {
+ return formatToFloatGeneric(v, format, date1904)
+}
+
+// based on %.2E, exponent? Yep, scientific notation. For this, I guess it is
+// for floats, probably not integrals. Return as float.
+func formatToEGeneric(v, format string, date1904 bool) any {
+ if strings.Contains(v, "_") {
+ fmt.Printf("formatToEGeneric: v %s, format %s, date1904 %s: error -420691116\n", v, format, date1904)
+ return -420691116
+ }
+ f, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ fmt.Printf("formatToEGeneric: v %s, format %s, date1904 %s: error -420691116\n", v, format, date1904)
+ return -420691117
+ }
+ return f
+}
+
+func formatGeneric(v, format string, date1904 bool) any {
+ // Here we enumerate the possible format strings, and give either
+ // time.Time or int returns for them.
+ switch format {
+ case "\"TRUE\";\"TRUE\";\"FALSE\"":
+ if v == "0" { return false } else if v == "1" { return true } else {
+ // Error case.
+ fmt.Println("f in chat: %v cannot be parsed bool with %v", v, format)
+ }
+ case "General", "#,##0", "#,##0.00", "0", "0%", "0.00%", "0.00e+00":
+ return parseIOrF64(v)
+ case "d\\-mmm\\-yy", "[$-809]dd/mm/yy", "[$-809]mm/dd/yy", "mm/dd/yy",
+ "mm-dd-yy", "d-mmm-yy", "d-mmm", "mmm-yy", "h:mm am/pm",
+ "h:mm:ss am/pm", "hh:mm", "hh:mm:ss", "m/d/y hh:mm":
+ // If it's an integer, it's a complete date. We don't really
+ // need to care about preserving time, which is the fractional
+ // component: yet! TODO: care about the fractional component,
+ // but for now let's just parse as is.
+ // We just need to convert Excel integer time to our format.
+ xlTime, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ fmt.Printf("formatGeneric: f in chat for %v, which can't be parsed into float in %v case statement; %v error", v, format, err)
+ panic("panic! formatGeneric") // TODO: handle this error better.
+ }
+ f := timeFromExcelTime(xlTime, date1904)
+ return f
+ default:
+ // Default: just parse integer or float! Though this is not a
+ // perfect solution.
+ fmt.Println("Ok, running default case")
+ return parseIOrF64(v)
+ }
+ return -420699999
+}
+
+/* pure */ func parseIOrF64(v string) any {
+ gv, err := strconv.ParseInt(v, 10, 64)
+ if err != nil {
+ fv, err := strconv.ParseFloat(v, 64)
+ if err != nil {
+ // What do?
+ fmt.Printf("formatGeneric: general format cannot parse as int or float [%v]\n", v)
+ return "parseIOrF64 fail"
+ }
+ return fv
+ }
+ return gv
+}
+
+// NOTE
+// This is re-writing these as these are functions that read into strings for
+// reading. I am not sure if they are used for writing, but if so eh. Probably
+// not as writing can manage with the actual types.