PHP Classes

File: extension/compat/values.go

Recommend this page to a friend!
  Packages of Roni   Easy-Excel   extension/compat/values.go   Download  
File: extension/compat/values.go
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Easy-Excel
Export and read XLSX files with a PHP Go extension
Author: By
Last change:
Date: 6 days ago
Size: 4,469 bytes
 

Contents

Class file image Download
// Package compat reproduces PhpSpreadsheet semantics on the Go side // (PLAN.md §4 compat layer). Divergences are documented in COMPAT.md. package compat import ( "fmt" "regexp" "strconv" ) // Kind classifies a bound cell value. type Kind byte const ( Skip Kind = iota // PHP null: leave the cell untouched Str // inline/shared string Num // float64 Boolean // bool Formula // formula source without the leading '=' ) // Cell is a bound value ready for the excelize adapter. type Cell struct { Kind Kind Str string Num float64 Bool bool } // Explicit type markers used by the PHP shim to encode // setCellValueExplicit() cells inside batched rows: a cell may be a // 2-element packed array [marker, value]. Markers start with "=" because no // PhpSpreadsheet DataType constant does, and arrays are never valid cell // values, so the encoding cannot collide with user data. const ( MarkString = "=s" MarkNumeric = "=n" MarkBool = "=b" MarkFormula = "=f" ) // PhpSpreadsheet DefaultValueBinder: strings matching this pattern are // stored as numbers, except integers with a leading zero (e.g. "01513"). var numericPattern = regexp.MustCompile(`^[+-]?(\d+\.?\d*|\d*\.?\d+)([eE][+-]?\d+)?$`) // Decode converts one cell slot received from PHP (a scalar, or an explicit // [marker, value] pair) into a bound Cell, mirroring DefaultValueBinder. func Decode(v any) (Cell, error) { if pair, ok := v.([]any); ok { return decodeExplicit(pair) } return bindScalar(v) } func bindScalar(v any) (Cell, error) { switch t := v.(type) { case nil: return Cell{Kind: Skip}, nil case bool: return Cell{Kind: Boolean, Bool: t}, nil case int64: return Cell{Kind: Num, Num: float64(t)}, nil case int: return Cell{Kind: Num, Num: float64(t)}, nil case float64: return Cell{Kind: Num, Num: t}, nil case string: return bindString(t), nil default: return Cell{}, fmt.Errorf("easy-excel: unsupported cell value of type %T", v) } } // bindString applies DefaultValueBinder::dataTypeForValue() rules. func bindString(s string) Cell { if len(s) > 1 && s[0] == '=' { return Cell{Kind: Formula, Str: s[1:]} } if isNumericString(s) { n, err := strconv.ParseFloat(s, 64) if err == nil { return Cell{Kind: Num, Num: n} } } return Cell{Kind: Str, Str: s} } func isNumericString(s string) bool { if !numericPattern.MatchString(s) { return false } // "0123" stays a string (leading zero, not a decimal like "0.5") digits := s if digits[0] == '+' || digits[0] == '-' { digits = digits[1:] } if len(digits) > 1 && digits[0] == '0' && digits[1] != '.' { return false } return true } func decodeExplicit(pair []any) (Cell, error) { if len(pair) != 2 { return Cell{}, fmt.Errorf("easy-excel: array cell values are not supported (explicit cells must be [marker, value] pairs)") } marker, ok := pair[0].(string) if !ok { return Cell{}, fmt.Errorf("easy-excel: invalid explicit cell marker of type %T", pair[0]) } v := pair[1] switch marker { case MarkString: return Cell{Kind: Str, Str: toString(v)}, nil case MarkFormula: s := toString(v) if len(s) > 0 && s[0] == '=' { s = s[1:] } return Cell{Kind: Formula, Str: s}, nil case MarkBool: switch b := v.(type) { case bool: return Cell{Kind: Boolean, Bool: b}, nil case int64: return Cell{Kind: Boolean, Bool: b != 0}, nil case float64: return Cell{Kind: Boolean, Bool: b != 0}, nil default: return Cell{Kind: Boolean, Bool: toString(v) != "" && toString(v) != "0"}, nil } case MarkNumeric: switch n := v.(type) { case int64: return Cell{Kind: Num, Num: float64(n)}, nil case int: return Cell{Kind: Num, Num: float64(n)}, nil case float64: return Cell{Kind: Num, Num: n}, nil case string: f, err := strconv.ParseFloat(n, 64) if err != nil { return Cell{}, fmt.Errorf("easy-excel: %q is not numeric", n) } return Cell{Kind: Num, Num: f}, nil default: return Cell{}, fmt.Errorf("easy-excel: cannot bind %T as numeric", v) } default: return Cell{}, fmt.Errorf("easy-excel: unknown explicit cell marker %q", marker) } } func toString(v any) string { switch t := v.(type) { case string: return t case nil: return "" case bool: if t { return "1" } return "0" case int64: return strconv.FormatInt(t, 10) case float64: return strconv.FormatFloat(t, 'G', -1, 64) default: return fmt.Sprint(t) } }