package utils import ( "encoding/binary" "math/rand" "net" "os" "reflect" "strconv" "strings" "time" ) //LowerFirst Make a string's first character lowercase func LowerFirst(s string) string { isFirst := true return strings.Map(func(r rune) rune { if isFirst && r >= 'A' && r <= 'Z' { r = r + 32 } isFirst = false return r }, s) } //UpperFirst Make a string's first character uppercase func UpperFirst(s string) string { isFirst := true return strings.Map(func(r rune) rune { if isFirst && r >= 'a' && r <= 'z' { r = r - 32 } isFirst = false return r }, s) } //InArray Checks if a value exists in an array func InArray(needle interface{}, haystack interface{}) bool { val := reflect.ValueOf(haystack) switch val.Kind() { case reflect.Slice, reflect.Array: for i := 0; i < val.Len(); i++ { if reflect.DeepEqual(needle, val.Index(i).Interface()) { return true } } case reflect.Map: for _, k := range val.MapKeys() { if reflect.DeepEqual(needle, val.MapIndex(k).Interface()) { return true } } default: panic("haystack: haystack type must be slice, array or map") } return false } //IsEmpty Determine whether a variable is empty func IsEmpty(val interface{}) bool { if val == nil { return true } v := reflect.ValueOf(val) switch v.Kind() { case reflect.String, reflect.Array: return v.Len() == 0 case reflect.Map, reflect.Slice: return v.Len() == 0 || v.IsNil() case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface()) } //IsNumeric Finds whether a variable is a number or a numeric string func IsNumeric(val interface{}) bool { switch val.(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: return true case float32, float64, complex64, complex128: return true case string: str := val.(string) if str == "" { return false } // Trim any whitespace str = strings.TrimSpace(str) if str[0] == '-' || str[0] == '+' { if len(str) == 1 { return false } str = str[1:] } // hex if len(str) > 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') { for _, h := range str[2:] { if !((h >= '0' && h <= '9') || (h >= 'a' && h <= 'f') || (h >= 'A' && h <= 'F')) { return false } } return true } // 0-9, Point, Scientific p, s, l := 0, 0, len(str) for i, v := range str { if v == '.' { // Point if p > 0 || s > 0 || i+1 == l { return false } p = i } else if v == 'e' || v == 'E' { // Scientific if i == 0 || s > 0 || i+1 == l { return false } s = i } else if v < '0' || v > '9' { return false } } return true } return false } //BreakUp break strings func BreakUp(s string) []string { length := len(s) b := make([]byte, length) ss := make([]string, 0) var p int for i := 0; i < length; i++ { if s[i] >= 'A' && s[i] <= 'Z' { if p > 0 { ss = append(ss, string(b[:p])) } p = 0 b[p] = s[i] + 32 } else { b[p] = s[i] } p++ } if p > 0 { ss = append(ss, string(b[:p])) } return ss } //Camel2id eg SendMail into send-mail func Camel2id(s string) string { return strings.Join(BreakUp(s), "-") } //Rand Generate a random integer func Rand(min, max int) int { if min > max { panic("min: min cannot be greater than max") } if int31 := 1<<31 - 1; max > int31 { panic("max: max can not be greater than " + strconv.Itoa(int31)) } if min == max { return min } r := rand.New(rand.NewSource(time.Now().UnixNano())) return r.Intn(max+1-min) + min } //FileExists Checks whether a file or directory exists func FileExists(filename string) bool { if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { return false } return true } //IsDir Tells whether the filename is a directory func IsDir(filename string) (bool, error) { fd, err := os.Stat(filename) if err != nil { return false, err } fm := fd.Mode() return fm.IsDir(), nil } //SimilarText Calculate the similarity between two strings func SimilarText(first, second string, percent *float64) int { var similarText func(string, string, int, int) int similarText = func(str1, str2 string, len1, len2 int) int { var sum, max int pos1, pos2 := 0, 0 // Find the longest segment of the same section in two strings for i := 0; i < len1; i++ { for j := 0; j < len2; j++ { for l := 0; (i+l < len1) && (j+l < len2) && (str1[i+l] == str2[j+l]); l++ { if l+1 > max { max = l + 1 pos1 = i pos2 = j } } } } if sum = max; sum > 0 { if pos1 > 0 && pos2 > 0 { sum += similarText(str1, str2, pos1, pos2) } if (pos1+max < len1) && (pos2+max < len2) { s1 := []byte(str1) s2 := []byte(str2) sum += similarText(string(s1[pos1+max:]), string(s2[pos2+max:]), len1-pos1-max, len2-pos2-max) } } return sum } l1, l2 := len(first), len(second) if l1+l2 == 0 { return 0 } sim := similarText(first, second, l1, l2) if percent != nil { *percent = float64(sim*200) / float64(l1+l2) } return sim } //IP2long Converts a string containing an (IPv4) Internet Protocol dotted address into a long integer func IP2long(ipAddress string) uint32 { ip := net.ParseIP(ipAddress) if ip == nil { return 0 } return binary.BigEndian.Uint32(ip.To4()) } //Long2IP Converts an long integer address into a string in (IPv4) Internet standard dotted format func Long2IP(properAddress uint32) string { ipByte := make([]byte, 4) binary.BigEndian.PutUint32(ipByte, properAddress) ip := net.IP(ipByte) return ip.String() }