Files

221 lines
4.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package excel
import (
"fmt"
"math"
"strconv"
"strings"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
)
func NormalizeHeader(header string) string {
header = strings.ReplaceAll(header, "\uFEFF", "")
header = strings.TrimSpace(header)
header = strings.TrimRight(header, "**")
return strings.ToUpper(strings.TrimSpace(header))
}
func ParseString(value string) string {
return strings.TrimSpace(value)
}
func ParseInt(value string) (int, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, strconv.ErrSyntax
}
return strconv.Atoi(value)
}
func ParsePositiveInt(value string) (int, error) {
parsed, err := ParseInt(value)
if err != nil || parsed <= 0 {
return 0, strconv.ErrSyntax
}
return parsed, nil
}
func ParseNonNegativeInt(value string) (int, error) {
parsed, err := ParseInt(value)
if err != nil || parsed < 0 {
return 0, strconv.ErrSyntax
}
return parsed, nil
}
func ParseBool(value string) (bool, error) {
switch strings.ToLower(strings.TrimSpace(value)) {
case "1", "true", "yes", "y", "\u662f", "\u5df2\u5b8c\u6210", "\u5b8c\u6210":
return true, nil
case "0", "false", "no", "n", "\u5426", "\u672a\u5b8c\u6210":
return false, nil
default:
return false, strconv.ErrSyntax
}
}
func ParseDate(value string) (*gtime.Time, error) {
parsed, err := parseTimeValue(value)
if err != nil {
return nil, err
}
return gtime.NewFromTime(time.Date(
parsed.Year(),
time.Month(parsed.Month()),
parsed.Day(),
0,
0,
0,
0,
parsed.Location(),
)), nil
}
func ParseDateTime(value string) (*gtime.Time, error) {
return parseTimeValue(value)
}
func ParseAmount(value string) (float64, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, strconv.ErrSyntax
}
value = strings.ReplaceAll(value, ",", "")
parsed, err := strconv.ParseFloat(value, 64)
if err != nil || parsed < 0 {
return 0, strconv.ErrSyntax
}
return math.Round(parsed*100) / 100, nil
}
func normalizedValue(value string, typ ColumnType) (string, error) {
switch typ {
case "", ColumnTypeString:
return ParseString(value), nil
case ColumnTypeInt:
parsed, err := ParseInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypePositiveInt:
parsed, err := ParsePositiveInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypeNonNegativeInt:
parsed, err := ParseNonNegativeInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypeBool:
parsed, err := ParseBool(value)
if err != nil {
return "", err
}
return strconv.FormatBool(parsed), nil
case ColumnTypeDate:
parsed, err := ParseDate(value)
if err != nil {
return "", err
}
return parsed.Format("Y-m-d"), nil
case ColumnTypeDateTime:
parsed, err := ParseDateTime(value)
if err != nil {
return "", err
}
return parsed.Format("Y-m-d H:i:s"), nil
case ColumnTypeAmount:
parsed, err := ParseAmount(value)
if err != nil {
return "", err
}
return fmt.Sprintf("%.2f", parsed), nil
default:
return "", gerror.Newf("unsupported column type: %s", typ)
}
}
func parseTimeValue(value string) (*gtime.Time, error) {
value = strings.TrimSpace(value)
if value == "" {
return nil, strconv.ErrSyntax
}
if parsed, ok := parseCompactTime(value); ok {
return parsed, nil
}
if parsed, ok := parseLayoutTime(value); ok {
return parsed, nil
}
parsed, err := gtime.StrToTime(value)
if err != nil || parsed == nil || parsed.IsZero() || parsed.Year() <= 0 {
if err != nil {
return nil, err
}
return nil, strconv.ErrSyntax
}
return parsed, nil
}
func parseCompactTime(value string) (*gtime.Time, bool) {
if !isDigits(value) {
return nil, false
}
layout := ""
switch len(value) {
case 8:
layout = "20060102"
case 12:
layout = "200601021504"
case 14:
layout = "20060102150405"
default:
return nil, false
}
parsed, err := time.ParseInLocation(layout, value, time.Local)
if err != nil {
return nil, false
}
return gtime.NewFromTime(parsed), true
}
func parseLayoutTime(value string) (*gtime.Time, bool) {
layouts := []string{
time.RFC3339,
time.RFC3339Nano,
"2006-1-2 15:04:05",
"2006-1-2 15:04",
"2006/1/2 15:04:05",
"2006/1/2 15:04",
"2006.1.2 15:04:05",
"2006.1.2 15:04",
"2006-1-2T15:04:05",
"2006-1-2T15:04",
"2006-1-2",
"2006/1/2",
"2006.1.2",
}
for _, layout := range layouts {
parsed, err := time.ParseInLocation(layout, value, time.Local)
if err == nil {
return gtime.NewFromTime(parsed), true
}
}
return nil, false
}
func isDigits(value string) bool {
for _, r := range value {
if r < '0' || r > '9' {
return false
}
}
return value != ""
}