diff --git a/CHANGELOG.md b/CHANGELOG.md index 0698ff60..330f7fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## v1.0.29 / 2021-12-20 + +- 增加int方法 +- 增加int64方法 +- 优化md5方法 +- 增加php方法 + ## v1.0.28 / 2021-12-18 - 优化随机数方法 diff --git a/LICENSE b/LICENSE index 34366fbe..ff84bbf0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 李光春 +Copyright (c) 2018 李光春 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b4db0875..b7adf12a 100644 --- a/README.md +++ b/README.md @@ -11,5 +11,5 @@ ## Install 安装 ```Importing -go get -v -u github.com/dtapps/go-library@v1.0.28 +go get -v -u github.com/dtapps/go-library@v1.0.29 ``` diff --git a/utils/goint/goint.go b/utils/goint/goint.go new file mode 100644 index 00000000..2cc1f290 --- /dev/null +++ b/utils/goint/goint.go @@ -0,0 +1,16 @@ +package goint + +import ( + "math" + "strconv" +) + +// ToString int到string +func ToString(n int) string { + return strconv.Itoa(n) +} + +// ToFloat64 int到float64 +func ToFloat64(n int) float64 { + return float64(n) / math.Pow10(0) +} diff --git a/utils/goint/goint_test.go b/utils/goint/goint_test.go new file mode 100644 index 00000000..f310a017 --- /dev/null +++ b/utils/goint/goint_test.go @@ -0,0 +1,14 @@ +package goint + +import ( + "fmt" + "testing" +) + +func TestToString(t *testing.T) { + fmt.Println(ToString(2222)) +} + +func TestToFloat64(t *testing.T) { + fmt.Println(ToFloat64(2222)) +} diff --git a/utils/goint64/goint64.go b/utils/goint64/goint64.go new file mode 100644 index 00000000..20fe1aac --- /dev/null +++ b/utils/goint64/goint64.go @@ -0,0 +1,23 @@ +package goint64 + +import "math" + +// ToFloat64 int64到float64 +func ToFloat64(n int64) float64 { + return float64(n) / math.Pow10(0) +} + +// ToUnwrap 将int64恢复成正常的float64 +func ToUnwrap(num int64, retain int) float64 { + return float64(num) / math.Pow10(retain) +} + +// ToUnwrapToInt64 精准int64 +func ToUnwrapToInt64(num int64, retain int) int64 { + return int64(ToUnwrap(num, retain)) +} + +// ToFloat64NewWiFi 返回float64 +func ToFloat64NewWiFi(num int64) float64 { + return float64(num / 100) +} diff --git a/utils/goless/goless.go b/utils/goless/goless.go new file mode 100644 index 00000000..d765d20a --- /dev/null +++ b/utils/goless/goless.go @@ -0,0 +1,45 @@ +package goless + +import ( + "reflect" + "strings" +) + +func NumericalValue(value reflect.Value) (float64, bool) { + switch value.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(value.Int()), true + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return float64(value.Uint()), true + + case reflect.Float32, reflect.Float64: + return value.Float(), true + + default: + return 0, false + } +} + +func LessValue(a, b reflect.Value) bool { + aValue, aNumerical := NumericalValue(a) + bValue, bNumerical := NumericalValue(b) + + if aNumerical && bNumerical { + return aValue < bValue + } + + if !aNumerical && !bNumerical { + // In theory this should mean they are both strings. In reality + // they could be any other type and the String() representation + // will be something like "" if it is not a string. Since + // distinct values of non-strings still return the same value + // here that's what makes the ordering undefined. + return strings.Compare(a.String(), b.String()) < 0 + } + + // Numerical values are always treated as less than other types + // (including strings that might represent numbers themselves). The + // inverse is also true. + return aNumerical && !bNumerical +} diff --git a/utils/md5/md5.go b/utils/gomd5/gomd5.go similarity index 74% rename from utils/md5/md5.go rename to utils/gomd5/gomd5.go index 3013168a..84201a5f 100644 --- a/utils/md5/md5.go +++ b/utils/gomd5/gomd5.go @@ -1,18 +1,27 @@ -package md5 +package gomd5 import ( "crypto/md5" "encoding/hex" + "fmt" + "io" "strings" ) +func Php(str string) string { + h := md5.New() + io.WriteString(h, str) + return fmt.Sprintf("%x", h.Sum(nil)) +} + func Md5(str string) string { s := md5.New() s.Write([]byte(str)) return hex.EncodeToString(s.Sum(nil)) } -func Md5ToUpper(str string) string { +// ToUpper md5加密后转大写 +func ToUpper(str string) string { h := md5.New() h.Write([]byte(str)) cipherStr := h.Sum(nil) diff --git a/utils/gomd5/gomd5_test.go b/utils/gomd5/gomd5_test.go new file mode 100644 index 00000000..2740662a --- /dev/null +++ b/utils/gomd5/gomd5_test.go @@ -0,0 +1,12 @@ +package gomd5 + +import ( + "fmt" + "testing" +) + +func TestMd5(t *testing.T) { + fmt.Println(GetMD5Encode("测试")) + fmt.Println(ToUpper(GetMD5Encode("测试"))) + fmt.Println(ToUpper("测试")) +} diff --git a/utils/gophp/gophp.go b/utils/gophp/gophp.go new file mode 100644 index 00000000..834ff7be --- /dev/null +++ b/utils/gophp/gophp.go @@ -0,0 +1,13 @@ +package gophp + +import "github.com/dtapps/go-library/utils/gophp/serialize" + +// Serialize 序列 +func Serialize(value interface{}) ([]byte, error) { + return serialize.Marshal(value) +} + +// Unserialize 反序列 +func Unserialize(data []byte) (interface{}, error) { + return serialize.UnMarshal(data) +} diff --git a/utils/gophp/gophp_test.go b/utils/gophp/gophp_test.go new file mode 100644 index 00000000..7e18c17d --- /dev/null +++ b/utils/gophp/gophp_test.go @@ -0,0 +1,32 @@ +package gophp + +import ( + "encoding/json" + "fmt" + "testing" +) + +func TestPhp(t *testing.T) { + fmt.Println(Unserialize([]byte(`a:1:{s:4:"test";i:34343;}`))) + serialize, _ := Serialize(map[string]interface{}{ + "test": 34343, + }) + fmt.Println(string(serialize)) +} + +type student struct { + Amount string `json:"amount"` + CreateTime string `json:"create_time"` + UpdateTime string `json:"update_time"` + UserID string `json:"user_id"` +} + +func TestUnserialize(t *testing.T) { + unserialize, _ := Unserialize([]byte(`a:2:{i:0;a:4:{s:7:"user_id";s:5:"10118";s:6:"amount";s:5:"69.00";s:11:"create_time";s:19:"2021-01-04 16:29:03";s:11:"update_time";s:19:"2021-06-15 16:02:46";}i:1;a:4:{s:7:"user_id";s:5:"10088";s:6:"amount";s:5:"10.00";s:11:"create_time";s:19:"2021-01-04 15:46:10";s:11:"update_time";s:19:"2021-06-15 15:50:06";}}`)) + fmt.Printf("%s\n", unserialize) + arr, _ := json.Marshal(unserialize) + fmt.Printf("arr:%s\n", arr) + var stu []student + _ = json.Unmarshal(arr, &stu) + fmt.Printf("stu:%v\n", stu) +} diff --git a/utils/gophp/serialize/serialize.go b/utils/gophp/serialize/serialize.go new file mode 100644 index 00000000..5015c1f8 --- /dev/null +++ b/utils/gophp/serialize/serialize.go @@ -0,0 +1,109 @@ +package serialize + +import ( + "bytes" + "fmt" + "github.com/dtapps/go-library/utils/goless" + "github.com/dtapps/go-library/utils/gostring" + "reflect" + "sort" +) + +func Marshal(value interface{}) ([]byte, error) { + if value == nil { + return MarshalNil(), nil + } + t := reflect.TypeOf(value) + switch t.Kind() { + case reflect.Bool: + return MarshalBool(value.(bool)), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + return MarshalNumber(value), nil + case reflect.String: + return MarshalString(value.(string)), nil + case reflect.Map: + return MarshalMap(value) + case reflect.Slice: + return MarshalSlice(value) + default: + return nil, fmt.Errorf("marshal: Unknown type %T with value %#v", t, value) + } +} + +func MarshalNil() []byte { + return []byte("N;") +} + +func MarshalBool(value bool) []byte { + if value { + return []byte("b:1;") + } + return []byte("b:0;") +} + +func MarshalNumber(value interface{}) []byte { + var val string + isFloat := false + switch value.(type) { + default: + val = "0" + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + val, _ = gostring.NumericalToString(value) + case float32, float64: + val, _ = gostring.NumericalToString(value) + isFloat = true + } + if isFloat { + return []byte("d:" + val + ";") + + } else { + return []byte("i:" + val + ";") + } +} + +func MarshalString(value string) []byte { + return []byte(fmt.Sprintf("s:%d:\"%s\";", len(value), value)) +} + +func MarshalMap(value interface{}) ([]byte, error) { + s := reflect.ValueOf(value) + mapKeys := s.MapKeys() + sort.Slice(mapKeys, func(i, j int) bool { + return goless.LessValue(mapKeys[i], mapKeys[j]) + }) + var buffer bytes.Buffer + for _, mapKey := range mapKeys { + m, err := Marshal(mapKey.Interface()) + if err != nil { + return nil, err + } + buffer.Write(m) + + m, err = Marshal(s.MapIndex(mapKey).Interface()) + if err != nil { + return nil, err + } + buffer.Write(m) + } + return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil +} + +func MarshalSlice(value interface{}) ([]byte, error) { + s := reflect.ValueOf(value) + var buffer bytes.Buffer + for i := 0; i < s.Len(); i++ { + m, err := Marshal(i) + if err != nil { + return nil, err + } + buffer.Write(m) + m, err = Marshal(s.Index(i).Interface()) + if err != nil { + return nil, err + } + buffer.Write(m) + } + return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil +} diff --git a/utils/gophp/serialize/unserialize.go b/utils/gophp/serialize/unserialize.go new file mode 100644 index 00000000..8988e7a5 --- /dev/null +++ b/utils/gophp/serialize/unserialize.go @@ -0,0 +1,227 @@ +package serialize + +import ( + "bytes" + "fmt" + "github.com/dtapps/go-library/utils/gostring" + "strconv" +) + +const UnserializableObjectMaxLen = int64(10 * 1024 * 1024 * 1024) + +func UnMarshal(data []byte) (interface{}, error) { + reader := bytes.NewReader(data) + return unMarshalByReader(reader) +} + +func unMarshalByReader(reader *bytes.Reader) (interface{}, error) { + for { + if token, _, err := reader.ReadRune(); err == nil { + switch token { + default: + return nil, fmt.Errorf("UnMarshal: Unknown token %#U", token) + case 'N': + return unMarshalNil(reader) + case 'b': + return unMarshalBool(reader) + case 'i': + return unMarshalNumber(reader, false) + case 'd': + return unMarshalNumber(reader, true) + case 's': + return unMarshalString(reader, true) + case 'a': + return unMarshalArray(reader) + } + } + return nil, nil + } +} + +func unMarshalNil(reader *bytes.Reader) (interface{}, error) { + err := expect(reader, ';') + if err != nil { + return nil, err + } + return nil, nil +} + +func unMarshalBool(reader *bytes.Reader) (interface{}, error) { + var ( + raw rune + err error + ) + err = expect(reader, ':') + if err != nil { + return nil, err + } + if raw, _, err = reader.ReadRune(); err != nil { + return nil, fmt.Errorf("UnMarshal: Error while reading bool value: %v", err) + } + err = expect(reader, ';') + if err != nil { + return nil, err + } + return raw == '1', nil +} + +func unMarshalNumber(reader *bytes.Reader, isFloat bool) (interface{}, error) { + var ( + raw string + err error + val interface{} + ) + err = expect(reader, ':') + if err != nil { + return nil, err + } + if raw, err = readUntil(reader, ';'); err != nil { + return nil, fmt.Errorf("UnMarshal: Error while reading number value: %v", err) + } else { + if isFloat { + if val, err = strconv.ParseFloat(raw, 64); err != nil { + return nil, fmt.Errorf("UnMarshal: Unable to convert %s to float: %v", raw, err) + } + } else { + if val, err = strconv.Atoi(raw); err != nil { + return nil, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) + } + } + } + return val, nil +} + +func unMarshalString(reader *bytes.Reader, isFinal bool) (interface{}, error) { + var ( + err error + val interface{} + strLen int + readLen int + ) + strLen, err = readLength(reader) + err = expect(reader, '"') + if err != nil { + return nil, err + } + if strLen > 0 { + buf := make([]byte, strLen, strLen) + if readLen, err = reader.Read(buf); err != nil { + return nil, fmt.Errorf("UnMarshal: Error while reading string value: %v", err) + } else { + if readLen != strLen { + return nil, fmt.Errorf("UnMarshal: Unable to read string. Expected %d but have got %d bytes", strLen, readLen) + } else { + val = string(buf) + } + } + } + err = expect(reader, '"') + if err != nil { + return nil, err + } + if isFinal { + err = expect(reader, ';') + if err != nil { + return nil, err + } + } + return val, nil +} + +func unMarshalArray(reader *bytes.Reader) (interface{}, error) { + var arrLen int + var err error + val := make(map[string]interface{}) + arrLen, err = readLength(reader) + if err != nil { + return nil, err + } + err = expect(reader, '{') + if err != nil { + return nil, err + } + indexLen := 0 + for i := 0; i < arrLen; i++ { + k, err := unMarshalByReader(reader) + if err != nil { + return nil, err + } + v, err := unMarshalByReader(reader) + if err != nil { + return nil, err + } + switch t := k.(type) { + default: + return nil, fmt.Errorf("UnMarshal: Unexpected key type %T", t) + case string: + stringKey, _ := k.(string) + val[stringKey] = v + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: + stringKey, _ := gostring.NumericalToString(k) + val[stringKey] = v + if i == k { + indexLen++ + } + } + } + err = expect(reader, '}') + if err != nil { + return nil, err + } + if indexLen == arrLen { + var slice []interface{} + for _, row := range val { + slice = append(slice, row) + } + return slice, nil + } + return val, nil +} + +func expect(reader *bytes.Reader, expected rune) error { + if token, _, err := reader.ReadRune(); err != nil { + return fmt.Errorf("UnMarshal: Error while reading expected rune %#U: %v", expected, err) + } else if token != expected { + return fmt.Errorf("UnMarshal: Expected %#U but have got %#U", expected, token) + } + return nil +} + +func readUntil(reader *bytes.Reader, stop rune) (string, error) { + var ( + token rune + err error + ) + buf := bytes.NewBuffer([]byte{}) + for { + if token, _, err = reader.ReadRune(); err != nil || token == stop { + break + } else { + buf.WriteRune(token) + } + } + return buf.String(), err +} + +func readLength(reader *bytes.Reader) (int, error) { + var ( + raw string + err error + val int + ) + err = expect(reader, ':') + if err != nil { + return 0, err + } + if raw, err = readUntil(reader, ':'); err != nil { + return 0, fmt.Errorf("UnMarshal: Error while reading lenght of value: %v", err) + } else { + if val, err = strconv.Atoi(raw); err != nil { + return 0, fmt.Errorf("UnMarshal: Unable to convert %s to int: %v", raw, err) + } else if int64(val) > UnserializableObjectMaxLen { + return 0, fmt.Errorf("UnMarshal: Unserializable object length looks too big(%d). If you are sure you wanna unserialise it, please increase UNSERIALIZABLE_OBJECT_MAX_LEN const", val) + val = 0 + } + } + return val, nil +} diff --git a/utils/md5/md5_test.go b/utils/md5/md5_test.go deleted file mode 100644 index 92ce521b..00000000 --- a/utils/md5/md5_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package md5 - -import ( - "fmt" - "testing" -) - -func TestName(t *testing.T) { - fmt.Println(Md5("测试")) -} diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..d4b585bf --- /dev/null +++ b/utils/utils.go @@ -0,0 +1 @@ +package utils