178 lines
5.0 KiB
Go
178 lines
5.0 KiB
Go
package isx
|
|
|
|
import (
|
|
"bytes"
|
|
"net/url"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
"unicode/utf8"
|
|
|
|
"git.cloudyne.io/go/hiscaler-gox/stringx"
|
|
)
|
|
|
|
var (
|
|
rxSafeCharacters = regexp.MustCompile("^[a-zA-Z0-9\\.\\-_][a-zA-Z0-9\\.\\-_]*$")
|
|
rxNumber = regexp.MustCompile("^[+-]?\\d+$|^\\d+[.]\\d+$")
|
|
rxColorHex = regexp.MustCompile("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")
|
|
)
|
|
|
|
// OS type
|
|
const (
|
|
IsAix = "aix"
|
|
IsAndroid = "android"
|
|
IsDarwin = "darwin"
|
|
IsDragonfly = "dragonfly"
|
|
IsFreebsd = "freebsd"
|
|
IsHurd = "hurd"
|
|
IsIllumos = "illumos"
|
|
IsIos = "ios"
|
|
IsJs = "js"
|
|
IsLinux = "linux"
|
|
IsNacl = "nacl"
|
|
IsNetbsd = "netbsd"
|
|
IsOpenbsd = "openbsd"
|
|
IsPlan9 = "plan9"
|
|
IsSolaris = "solaris"
|
|
IsWindows = "windows"
|
|
IsZos = "zos"
|
|
)
|
|
|
|
// Number Check any value is a number
|
|
func Number(i interface{}) bool {
|
|
switch i.(type) {
|
|
case string:
|
|
s := stringx.TrimAny(strings.TrimSpace(i.(string)), "+", "-")
|
|
n := len(s)
|
|
if n == 0 {
|
|
return false
|
|
}
|
|
|
|
if strings.IndexFunc(s[n-1:], func(c rune) bool {
|
|
return c < '0' || c > '9'
|
|
}) != -1 {
|
|
return false
|
|
}
|
|
return rxNumber.MatchString(strings.ReplaceAll(s, ",", ""))
|
|
case int, int8, int16, int32, int64,
|
|
uint, uint8, uint16, uint32, uint64, uintptr,
|
|
float32, float64,
|
|
complex64, complex128:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Empty 判断是否为空
|
|
func Empty(value interface{}) bool {
|
|
if value == nil {
|
|
return true
|
|
}
|
|
|
|
v := reflect.ValueOf(value)
|
|
switch v.Kind() {
|
|
case reflect.String, reflect.Array, reflect.Map, reflect.Slice:
|
|
return v.Len() == 0
|
|
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.Invalid:
|
|
return true
|
|
case reflect.Interface, reflect.Ptr:
|
|
if v.IsNil() {
|
|
return true
|
|
}
|
|
return Empty(v.Elem().Interface())
|
|
case reflect.Struct:
|
|
v, ok := value.(time.Time)
|
|
if ok && v.IsZero() {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func Equal(expected interface{}, actual interface{}) bool {
|
|
if expected == nil || actual == nil {
|
|
return expected == actual
|
|
}
|
|
|
|
if exp, ok := expected.([]byte); ok {
|
|
act, ok := actual.([]byte)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if exp == nil || act == nil {
|
|
return true
|
|
}
|
|
|
|
return bytes.Equal(exp, act)
|
|
}
|
|
return reflect.DeepEqual(expected, actual)
|
|
}
|
|
|
|
// SafeCharacters Only include a-zA-Z0-9.-_
|
|
// Reference https://www.quora.com/What-are-valid-file-names
|
|
func SafeCharacters(str string) bool {
|
|
if str == "" {
|
|
return false
|
|
}
|
|
return rxSafeCharacters.MatchString(str)
|
|
}
|
|
|
|
// HttpURL checks if the string is a HTTP URL.
|
|
// govalidator/IsURL
|
|
func HttpURL(str string) bool {
|
|
const (
|
|
URLSchema string = `((https?):\/\/)`
|
|
URLPath string = `((\/|\?|#)[^\s]*)`
|
|
URLPort string = `(:(\d{1,5}))`
|
|
URLIP string = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))`
|
|
URLSubdomain string = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
|
|
URL = `^` + URLSchema + `?` + `((` + URLIP + `|(\[` + `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
|
|
)
|
|
|
|
if str == "" || utf8.RuneCountInString(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") {
|
|
return false
|
|
}
|
|
if strings.HasPrefix(str, "//") {
|
|
str = "http:" + str
|
|
}
|
|
strTemp := str
|
|
if strings.Contains(str, ":") && !strings.Contains(str, "://") {
|
|
// support no indicated urlscheme but with colon for port number
|
|
// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
|
|
strTemp = "http://" + str
|
|
}
|
|
u, err := url.Parse(strTemp)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
if strings.HasPrefix(u.Host, ".") {
|
|
return false
|
|
}
|
|
if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
|
|
return false
|
|
}
|
|
return regexp.MustCompile(URL).MatchString(str)
|
|
}
|
|
|
|
// OS check typ is a valid OS type
|
|
// Usage: isx.OS(isx.IsLinux)
|
|
func OS(typ string) bool {
|
|
return runtime.GOOS == typ
|
|
}
|
|
|
|
func ColorHex(s string) bool {
|
|
return rxColorHex.MatchString(s)
|
|
}
|