You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
628 lines
13 KiB
628 lines
13 KiB
2 years ago
|
package xstring
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/base64"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"regexp"
|
||
|
"sort"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
func TableFieldNames(obj any) ([]string, string) {
|
||
|
v := reflect.TypeOf(obj)
|
||
|
cols := []string{}
|
||
|
primary := ""
|
||
|
for i := 0; i < v.NumField(); i++ {
|
||
|
cols = append(cols, v.Field(i).Tag.Get("db"))
|
||
|
if primary == "" {
|
||
|
primary = v.Field(i).Tag.Get("primaryKey")
|
||
|
}
|
||
|
}
|
||
|
return cols, primary
|
||
|
}
|
||
|
|
||
|
func Remove[T string](cols []T, key T) []T {
|
||
|
arr := make([]T, 0)
|
||
|
for _, v := range cols {
|
||
|
if key != v {
|
||
|
arr = append(arr, v)
|
||
|
}
|
||
|
}
|
||
|
return arr
|
||
|
}
|
||
|
|
||
|
func NamedSql(cls []string) string {
|
||
|
str := []string{}
|
||
|
for _, v := range cls {
|
||
|
str = append(str, fmt.Sprintf("%s=:%s", v, v))
|
||
|
}
|
||
|
return strings.Join(str, ",")
|
||
|
}
|
||
|
|
||
|
func StripTags(content string) string {
|
||
|
re := regexp.MustCompile(`<(.|\n)*?>`)
|
||
|
return re.ReplaceAllString(content, "")
|
||
|
}
|
||
|
func SubString(str string, begin, length int) string {
|
||
|
rs := []rune(str)
|
||
|
lth := len(rs)
|
||
|
if begin < 0 {
|
||
|
begin = 0
|
||
|
}
|
||
|
if begin >= lth {
|
||
|
begin = lth
|
||
|
}
|
||
|
end := begin + length
|
||
|
|
||
|
if end > lth {
|
||
|
end = lth
|
||
|
}
|
||
|
return string(rs[begin:end])
|
||
|
}
|
||
|
func Nl2br(str string) string {
|
||
|
return strings.Join(strings.Split(strings.Join(strings.Split(str, "\r"), "<br/>"), "\n"), "<br/>")
|
||
|
}
|
||
|
|
||
|
func Serialize(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, _ = NumericalToString(value)
|
||
|
case float32, float64:
|
||
|
val, _ = NumericalToString(value)
|
||
|
isFloat = true
|
||
|
}
|
||
|
|
||
|
if isFloat {
|
||
|
return []byte("d:" + val + ";")
|
||
|
|
||
|
} else {
|
||
|
return []byte("i:" + val + ";")
|
||
|
}
|
||
|
}
|
||
|
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 MarshalString(value string) []byte {
|
||
|
return []byte(fmt.Sprintf("s:%d:\"%s\";", len(value), value))
|
||
|
}
|
||
|
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 "<bool>" 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
|
||
|
}
|
||
|
|
||
|
func MarshalMap(value interface{}) ([]byte, error) {
|
||
|
|
||
|
s := reflect.ValueOf(value)
|
||
|
|
||
|
mapKeys := s.MapKeys()
|
||
|
sort.Slice(mapKeys, func(i, j int) bool {
|
||
|
return LessValue(mapKeys[i], mapKeys[j])
|
||
|
})
|
||
|
|
||
|
var buffer bytes.Buffer
|
||
|
for _, mapKey := range mapKeys {
|
||
|
m, err := Serialize(mapKey.Interface())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
buffer.Write(m)
|
||
|
|
||
|
m, err = Serialize(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 := Serialize(i)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
buffer.Write(m)
|
||
|
|
||
|
m, err = Serialize(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
|
||
|
}
|
||
|
|
||
|
const UNSERIALIZABLE_OBJECT_MAX_LEN = int64(10 * 1024 * 1024 * 1024)
|
||
|
|
||
|
func UnSerialize(data []byte) (interface{}, error) {
|
||
|
reader := bytes.NewReader(data)
|
||
|
return unMarshalByReader(reader)
|
||
|
}
|
||
|
|
||
|
func UnSerializeBind(data []byte, post any) error {
|
||
|
reader := bytes.NewReader(data)
|
||
|
b, err := unMarshalByReader(reader)
|
||
|
if err != nil {
|
||
2 years ago
|
return err
|
||
2 years ago
|
}
|
||
|
bb, err := json.Marshal(b)
|
||
|
if err != nil {
|
||
2 years ago
|
return err
|
||
2 years ago
|
}
|
||
2 years ago
|
return json.Unmarshal(bb, post)
|
||
2 years ago
|
}
|
||
|
|
||
|
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)
|
||
|
// case 'O':
|
||
|
|
||
|
// case 'C':
|
||
|
|
||
|
// case 'R', 'r':
|
||
|
|
||
|
// case 'x':
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func unMarshalNil(reader *bytes.Reader) (interface{}, error) {
|
||
|
_ = expect(reader, ';')
|
||
|
|
||
|
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)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
err = expect(reader, '"')
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if strLen > 0 {
|
||
|
buf := make([]byte, 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
|
||
|
}
|
||
|
|
||
|
// if errKey == nil && errVal == nil {
|
||
|
// val[k] = v
|
||
|
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:
|
||
|
// intKey, _ := k.(int)
|
||
|
// val[strconv.Itoa(intKey)] = v
|
||
|
stringKey, _ := NumericalToString(k)
|
||
|
val[stringKey] = v
|
||
|
|
||
|
// stringI, _ := utils.NumericalToString(i)
|
||
|
if i == k {
|
||
|
indexLen++
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// } else {
|
||
|
// return nil, fmt.Errorf("UnMarshal: Error while reading key or(and) value of array")
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
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) > UNSERIALIZABLE_OBJECT_MAX_LEN {
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
return val, nil
|
||
|
}
|
||
|
|
||
|
func NumericalToString(value interface{}) (string, bool) {
|
||
|
var val string
|
||
|
|
||
|
switch intVal := value.(type) {
|
||
|
default:
|
||
|
return "0", false
|
||
|
case int:
|
||
|
val = strconv.FormatInt(int64(intVal), 10)
|
||
|
case int8:
|
||
|
val = strconv.FormatInt(int64(intVal), 10)
|
||
|
case int16:
|
||
|
val = strconv.FormatInt(int64(intVal), 10)
|
||
|
case int32:
|
||
|
val = strconv.FormatInt(int64(intVal), 10)
|
||
|
case int64:
|
||
|
val = strconv.FormatInt(int64(intVal), 10)
|
||
|
case uint:
|
||
|
val = strconv.FormatUint(uint64(intVal), 10)
|
||
|
case uint8:
|
||
|
val = strconv.FormatUint(uint64(intVal), 10)
|
||
|
case uint16:
|
||
|
val = strconv.FormatUint(uint64(intVal), 10)
|
||
|
case uint32:
|
||
|
val = strconv.FormatUint(uint64(intVal), 10)
|
||
|
case uint64:
|
||
|
val = strconv.FormatUint(intVal, 10)
|
||
|
case float32:
|
||
|
val = strconv.FormatFloat(float64(intVal), 'f', -1, 32)
|
||
|
case float64:
|
||
|
val = strconv.FormatFloat(intVal, 'f', -1, 64)
|
||
|
}
|
||
|
return val, true
|
||
|
}
|
||
|
|
||
|
//func StrToArr(str string) []string {
|
||
|
// re := regexp.MustCompile(`<(.|\n)*?>`)
|
||
|
// str = re.ReplaceAllString(str, " ")
|
||
|
// str = strings.ReplaceAll(str, `"`, "")
|
||
|
// str = strings.ReplaceAll(str, `'`, "")
|
||
|
// str = strings.ReplaceAll(str, "`", "")
|
||
|
// str = strings.ReplaceAll(str, ",", "")
|
||
|
// str = strings.ReplaceAll(str, " ", "")
|
||
|
// newStr := []string{}
|
||
|
// tmp := ""
|
||
|
// for i := 0; i < len(str); {
|
||
|
// r, n := utf8.DecodeRuneInString(str[i:])
|
||
|
// if n == 3 {
|
||
|
// tmp = ""
|
||
|
// newStr = append(newStr, string(r))
|
||
|
// } else {
|
||
|
//
|
||
|
// if string(r) == " " {
|
||
|
// newStr = append(newStr, tmp)
|
||
|
// tmp = ""
|
||
|
// } else if string(r) != "\n" {
|
||
|
// tmp = fmt.Sprintf("%s%c", tmp, r)
|
||
|
// }
|
||
|
// }
|
||
|
// i += n
|
||
|
// }
|
||
|
// if tmp != "" {
|
||
|
// newStr = append(newStr, tmp)
|
||
|
// tmp = ""
|
||
|
// }
|
||
|
// newStr1 := make([]string, 0)
|
||
|
// for _, v := range newStr {
|
||
|
// if strings.TrimSpace(v) == "" {
|
||
|
// continue
|
||
|
// }
|
||
|
// newStr1 = append(newStr1, strings.TrimSpace(v))
|
||
|
// }
|
||
|
// return newStr1
|
||
|
//}
|
||
|
|
||
|
//func StrToUrl(str string) string {
|
||
|
// strs := []string{}
|
||
|
// for _, v := range StrToArr(str) {
|
||
|
// fmt.Println(v)
|
||
|
// }
|
||
|
//
|
||
|
// return strings.Join(strs, "-")
|
||
|
//}
|
||
|
|
||
|
func Base64Encode(s string) string {
|
||
|
return base64.StdEncoding.EncodeToString([]byte(s))
|
||
|
}
|
||
|
|
||
|
func Base64Decode(s string) (string, error) {
|
||
|
b, err := base64.StdEncoding.DecodeString(s)
|
||
|
if err != nil {
|
||
2 years ago
|
return "", err
|
||
2 years ago
|
}
|
||
|
return string(b), nil
|
||
|
}
|
||
|
|
||
|
func Ucfirst(str string) string {
|
||
|
for i, v := range str {
|
||
|
return string(unicode.ToUpper(v)) + str[i+1:]
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func Lcfirst(str string) string {
|
||
|
for i, v := range str {
|
||
|
return string(unicode.ToLower(v)) + str[i+1:]
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
2 years ago
|
|
||
|
func GetUrlRequestURI(url string) string {
|
||
|
urls := strings.Split(url, "?")
|
||
|
urls = strings.Split(urls[0], " ")
|
||
|
if len(urls) > 1 {
|
||
|
return urls[1]
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
2 years ago
|
|
||
|
func CoverInt64(str string) int64 {
|
||
|
i, _ := strconv.ParseInt(str, 10, 64)
|
||
|
return i
|
||
|
}
|
||
2 years ago
|
|
||
|
func ToInterfaceSlice(slice interface{}) []interface{} {
|
||
|
s := reflect.ValueOf(slice)
|
||
|
if s.Kind() != reflect.Slice {
|
||
|
panic("InterfaceSlice() given a non-slice type")
|
||
|
}
|
||
|
|
||
|
ret := make([]interface{}, s.Len())
|
||
|
|
||
|
for i := 0; i < s.Len(); i++ {
|
||
|
ret[i] = s.Index(i).Interface()
|
||
|
}
|
||
|
|
||
|
return ret
|
||
|
}
|