diff options
author | George Abbott <otg@gabbott.dev> | 2023-06-15 22:17:12 +0100 |
---|---|---|
committer | George Abbott <otg@gabbott.dev> | 2023-06-15 22:17:12 +0100 |
commit | 9987f77b7100bb5934faa7427d1a4acda866ff38 (patch) | |
tree | 6aa4da902be7f6af0d2926accd151b949f92d81d /formattedValue.go | |
parent | c4d71b0fdb4bef63e1553843efa9cb9ea9270806 (diff) |
excelize -> anyxcelizegetRowInterface
Diffstat (limited to 'formattedValue.go')
-rw-r--r-- | formattedValue.go | 257 |
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. |