package xstring
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"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, " ", "")
// 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 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 ""
}
func GetUrlRequestURI ( url string ) string {
urls := strings . Split ( url , "?" )
urls = strings . Split ( urls [ 0 ] , " " )
if len ( urls ) > 1 {
return urls [ 1 ]
}
return ""
}
func CoverInt64 ( str string ) int64 {
i , _ := strconv . ParseInt ( str , 10 , 64 )
return i
}