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.
 
 

655 lines
14 KiB

package xstring
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/PuerkitoBio/goquery"
"github.com/pkg/errors"
"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 {
return err
}
bb, err := json.Marshal(b)
if err != nil {
return err
}
return json.Unmarshal(bb, post)
}
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, "&nbsp;", "")
// 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 {
return "", errors.Wrap(err, "")
}
return string(b), nil
}
func HtmlToText(body string) ([]string, error) {
body = strings.ReplaceAll(body, "&nbsp;", " ")
ss := "<(.|\\n)*?>"
body = regexp.MustCompile(ss).ReplaceAllString(body, " ")
doc, err := goquery.NewDocumentFromReader(strings.NewReader(body))
if err != nil {
return nil, errors.Wrap(err, "")
}
defer doc.Clone()
v := doc.Text()
var hzRegexp = regexp.MustCompile("^[a-zA-Z0-9\u4e00-\u9fa5]$")
var zwReg = regexp.MustCompile("^[\u4e00-\u9fa5]$")
strn := ""
ars := []string{}
for _, c := range v {
filter := false
if hzRegexp.MatchString(string(c)) {
if zwReg.MatchString(string(c)) {
strn += string(c)
filter = true
} else {
strn += string(c)
}
} else {
filter = true
}
fmt.Println(strn)
if filter && strn != "" {
ars = append(ars, strn)
strn = ""
}
}
if strn != "" {
ars = append(ars, strn)
}
return ars, nil
}
func ContentText(body string) string {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(body))
if err != nil {
return err.Error()
}
defer doc.Clone()
return doc.Text()
}
func GetPicture(pic string) string {
if pic == "" {
return "/sites/default/files/imagecache/ic50x50/avatar_selection/o2QQW.jpg.png"
}
if !strings.HasPrefix(pic, "/") {
return "/" + pic
}
return pic
}
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 ""
}