package is
import (
"encoding/json"
"net"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"time"
)
// Email 验证给出的字符串是不是有效的邮箱地址
func Email ( str string ) bool {
return emailRegex . MatchString ( str )
}
// E164 判断给出的字符串是否符合 e.164 规范的手机号码
func E164 ( str string ) bool {
return e164Regex . MatchString ( str )
}
// PhoneNumber 判断给出的字符串是否符合中国大陆规范的手机号码
func PhoneNumber ( str string ) bool {
return phoneNumberRegex . MatchString ( str )
}
// Semver 判断给出的字符串是否符合语义化版本号规范
func Semver ( str string ) bool {
return semverRegex . MatchString ( str )
}
// Base64 判断给出的字符串是否为base64数据
func Base64 ( str string ) bool {
return base64Regex . MatchString ( str )
}
// URL 判断给出的字符串是否为有效的URL
func URL ( s string ) bool {
var i int
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i = strings . Index ( s , "#" ) ; i > - 1 {
s = s [ : i ]
}
if len ( s ) == 0 {
return false
}
u , err := url . ParseRequestURI ( s )
if err != nil || u . Scheme == "" {
return false
}
return true
}
// Base64URL 判断给出的字符串是否为有效且安全的 base64URL
func Base64URL ( str string ) bool {
return base64URLRegex . MatchString ( str )
}
// JWT is the validation function for validating if the current field's value is a valid JWT string.
func JWT ( str string ) bool {
return jWTRegex . MatchString ( str )
}
// UUID5 is the validation function for validating if the field's value is a valid v5 UUID.
func UUID5 ( str string ) bool {
return uUID5Regex . MatchString ( str )
}
// UUID4 is the validation function for validating if the field's value is a valid v4 UUID.
func UUID4 ( str string ) bool {
return uUID4Regex . MatchString ( str )
}
// UUID3 is the validation function for validating if the field's value is a valid v3 UUID.
func UUID3 ( str string ) bool {
return uUID3Regex . MatchString ( str )
}
// UUID is the validation function for validating if the field's value is a valid UUID of any version.
func UUID ( str string ) bool {
return uUIDRegex . MatchString ( str )
}
// ULID is the validation function for validating if the field's value is a valid ULID.
func ULID ( str string ) bool {
return uLIDRegex . MatchString ( str )
}
// MD4 is the validation function for validating if the field's value is a valid MD4.
func MD4 ( str string ) bool {
return md4Regex . MatchString ( str )
}
// MD5 is the validation function for validating if the field's value is a valid MD5.
func MD5 ( str string ) bool {
return md5Regex . MatchString ( str )
}
// SHA256 is the validation function for validating if the field's value is a valid SHA256.
func SHA256 ( str string ) bool {
return sha256Regex . MatchString ( str )
}
// SHA384 is the validation function for validating if the field's value is a valid SHA384.
func SHA384 ( str string ) bool {
return sha384Regex . MatchString ( str )
}
// SHA512 is the validation function for validating if the field's value is a valid SHA512.
func SHA512 ( str string ) bool {
return sha512Regex . MatchString ( str )
}
// ASCII is the validation function for validating if the field's value is a valid ASCII character.
func ASCII ( str string ) bool {
return aSCIIRegex . MatchString ( str )
}
// Alpha is the validation function for validating if the current field's value is a valid alpha value.
func Alpha ( str string ) bool {
return alphaRegex . MatchString ( str )
}
// Alphanumeric is the validation function for validating if the current field's value is a valid alphanumeric value.
func Alphanumeric ( str string ) bool {
return alphaNumericRegex . MatchString ( str )
}
// AlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
func AlphaUnicode ( str string ) bool {
return alphaUnicodeRegex . MatchString ( str )
}
// AlphanumericUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
func AlphanumericUnicode ( str string ) bool {
return alphaUnicodeNumericRegex . MatchString ( str )
}
// Numeric is the validation function for validating if the current field's value is a valid numeric value.
func Numeric [ T any ] ( t T ) bool {
ctx := reflect . ValueOf ( t )
switch ctx . Kind ( ) {
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 ,
reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr ,
reflect . Float32 , reflect . Float64 :
return true
default :
return numericRegex . MatchString ( ctx . String ( ) )
}
}
// Number is the validation function for validating if the current field's value is a valid number.
func Number [ T any ] ( t T ) bool {
rv := reflect . ValueOf ( t )
switch rv . Kind ( ) {
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 ,
reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr ,
reflect . Float32 , reflect . Float64 :
return true
default :
return numberRegex . MatchString ( rv . String ( ) )
}
}
// Boolean is the validation function for validating if the current field's value can be safely converted to a boolean.
func Boolean [ T any ] ( t T ) bool {
ref := reflect . ValueOf ( t )
switch ref . Kind ( ) {
case reflect . String :
switch ref . String ( ) {
case "1" , "yes" , "YES" , "Yes" , "on" , "ON" , "On" , "true" , "TRUE" , "True" ,
"0" , "no" , "NO" , "No" , "" , "off" , "OFF" , "Off" , "false" , "FALSE" , "False" :
return true
default :
return false
}
case reflect . Int , reflect . Int32 , reflect . Int64 :
n := ref . Int ( )
return n == 0 || n == 1
case reflect . Uint , reflect . Uint32 , reflect . Uint64 :
n := ref . Uint ( )
return n == 0 || n == 1
case reflect . Bool :
return ref . Bool ( )
}
return false
}
// Default is the opposite of required aka HasValue
func Default ( val any ) bool {
return ! HasValue ( val )
}
// HasValue is the validation function for validating if the current field's value is not the default static value.
func HasValue ( val any ) bool {
rv := reflect . ValueOf ( val )
switch rv . Kind ( ) {
case reflect . Slice , reflect . Map , reflect . Ptr , reflect . Interface , reflect . Chan , reflect . Func :
return ! rv . IsNil ( )
default :
return rv . IsValid ( ) && rv . Interface ( ) != reflect . Zero ( rv . Type ( ) ) . Interface ( )
}
}
// Hexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
func Hexadecimal ( str string ) bool {
return hexadecimalRegex . MatchString ( str )
}
// HEXColor is the validation function for validating if the current field's value is a valid HEX color.
func HEXColor ( str string ) bool {
return hexColorRegex . MatchString ( str )
}
// RGB is the validation function for validating if the current field's value is a valid RGB color.
func RGB ( str string ) bool {
return rgbRegex . MatchString ( str )
}
// RGBA is the validation function for validating if the current field's value is a valid RGBA color.
func RGBA ( str string ) bool {
return rgbaRegex . MatchString ( str )
}
// HSL is the validation function for validating if the current field's value is a valid HSL color.
func HSL ( str string ) bool {
return hslRegex . MatchString ( str )
}
// HSLA is the validation function for validating if the current field's value is a valid HSLA color.
func HSLA ( str string ) bool {
return hslaRegex . MatchString ( str )
}
func Color ( str string ) bool {
return HEXColor ( str ) || HSLA ( str ) || HSL ( str ) || RGB ( str ) || RGBA ( str )
}
// Latitude is the validation function for validating if the field's value is a valid latitude coordinate.
func Latitude [ T any ] ( t T ) bool {
ref := reflect . ValueOf ( t )
var v string
switch ref . Kind ( ) {
case reflect . String :
v = ref . String ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
v = strconv . FormatInt ( ref . Int ( ) , 10 )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
v = strconv . FormatUint ( ref . Uint ( ) , 10 )
case reflect . Float32 :
v = strconv . FormatFloat ( ref . Float ( ) , 'f' , - 1 , 32 )
case reflect . Float64 :
v = strconv . FormatFloat ( ref . Float ( ) , 'f' , - 1 , 64 )
default :
//fmt.Errorf("bad ref type %T", ref.Interface())
return false
}
return latitudeRegex . MatchString ( v )
}
// Longitude is the validation function for validating if the field's value is a valid longitude coordinate.
func Longitude [ T any ] ( t T ) bool {
ref := reflect . ValueOf ( t )
var v string
switch ref . Kind ( ) {
case reflect . String :
v = ref . String ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
v = strconv . FormatInt ( ref . Int ( ) , 10 )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
v = strconv . FormatUint ( ref . Uint ( ) , 10 )
case reflect . Float32 :
v = strconv . FormatFloat ( ref . Float ( ) , 'f' , - 1 , 32 )
case reflect . Float64 :
v = strconv . FormatFloat ( ref . Float ( ) , 'f' , - 1 , 64 )
default :
//fmt.Errorf("bad field type %T", ref.Interface())
return false
}
return longitudeRegex . MatchString ( v )
}
// JSON is the validation function for validating if the current field's value is a valid json string.
func JSON [ T any ] ( t T ) bool {
rv := reflect . ValueOf ( t )
if rv . Type ( ) == nilType {
return json . Valid ( rv . Bytes ( ) )
}
if rv . Kind ( ) == reflect . String {
return json . Valid ( [ ] byte ( rv . String ( ) ) )
}
return false
}
func Datetime ( str , layout string ) bool {
_ , err := time . Parse ( layout , str )
return err == nil
}
// Timezone is the validation function for validating if the current field's value is a valid time zone string.
func Timezone ( str string ) bool {
// empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name
if str == "" {
return false
}
// Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name
if strings . ToLower ( str ) == "local" {
return false
}
_ , err := time . LoadLocation ( str )
return err == nil
}
// IPv4 is the validation function for validating if a value is a valid v4 IP address.
func IPv4 ( str string ) bool {
ip := net . ParseIP ( str )
return ip != nil && ip . To4 ( ) != nil
}
// IPv6 is the validation function for validating if the field's value is a valid v6 IP address.
func IPv6 ( str string ) bool {
ip := net . ParseIP ( str )
return ip != nil && ip . To4 ( ) == nil
}
// IP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
func IP ( str string ) bool {
ip := net . ParseIP ( str )
return ip != nil
}
// MAC is the validation function for validating if the field's value is a valid MAC address.
func MAC ( str string ) bool {
_ , err := net . ParseMAC ( str )
return err == nil
}
// Lowercase is the validation function for validating if the current field's value is a lowercase string.
func Lowercase ( str string ) bool {
if str == "" {
return false
}
return str == strings . ToLower ( str )
}
// Uppercase is the validation function for validating if the current field's value is an uppercase string.
func Uppercase ( str string ) bool {
if str == "" {
return false
}
return str == strings . ToUpper ( str )
}
// Empty checks if a value is empty or not.
// A value is considered empty if
// - integer, float: zero
// - bool: false
// - string, array: len() == 0
// - slice, map: nil or len() == 0
// - interface, pointer: nil or the referenced value is empty
func Empty [ T any ] ( t T ) bool {
rv := reflect . ValueOf ( t )
switch rv . Kind ( ) {
case reflect . String , reflect . Array , reflect . Map , reflect . Slice :
return rv . Len ( ) == 0
case reflect . Bool :
return ! rv . Bool ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return rv . Int ( ) == 0
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return rv . Uint ( ) == 0
case reflect . Float32 , reflect . Float64 :
return rv . Float ( ) == 0
case reflect . Invalid :
return true
case reflect . Interface , reflect . Ptr :
if rv . IsNil ( ) {
return true
}
return Empty ( rv . Elem ( ) . Interface ( ) )
case reflect . Struct :
v , ok := rv . Interface ( ) . ( time . Time )
if ok && v . IsZero ( ) {
return true
}
}
return false
}
func NotEmpty [ T any ] ( t T ) bool {
return ! Empty ( t )
}
func URLEncoded ( str string ) bool {
return uRLEncodedRegex . MatchString ( str )
}
func HTMLEncoded ( str string ) bool {
return hTMLEncodedRegex . MatchString ( str )
}
func HTML ( str string ) bool {
return hTMLRegex . MatchString ( str )
}
// File is the validation function for validating if the current field's value is a valid file path.
func File ( val any ) bool {
field := reflect . ValueOf ( val )
switch field . Kind ( ) {
case reflect . String :
fileInfo , err := os . Stat ( field . String ( ) )
if err != nil {
return false
}
return ! fileInfo . IsDir ( )
}
//fmt.Errorf("bad value type %T", field.Interface())
return false
}
// Dir is the validation function for validating if the current field's value is a valid directory.
func Dir ( val any ) bool {
field := reflect . ValueOf ( val )
if field . Kind ( ) == reflect . String {
fileInfo , err := os . Stat ( field . String ( ) )
if err != nil {
return false
}
return fileInfo . IsDir ( )
}
//fmt.Errorf("bad field type %T", field.Interface())
return false
}
func OneOf ( val any , vals [ ] any ) bool {
//rv := reflect.ValueOf(val)
//
//var v string
//switch rv.Kind() {
//case reflect.String:
// v = rv.String()
//case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
// v = strconv.FormatInt(rv.Int(), 10)
//case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// v = strconv.FormatUint(rv.Uint(), 10)
//default:
// //fmt.Errorf("Bad rv type %T", rv.Interface())
// return false
//}
//for i := 0; i < len(vals); i++ {
// if vals[i] == v {
// return true
// }
//}
if len ( vals ) == 0 {
return false
}
for _ , a := range vals {
if Equal ( val , a ) {
return true
}
}
return false
}
func Length ( val any , length int , op string ) bool {
if n := calcLength ( val ) ; n == - 1 {
return false
} else {
return Compare ( n , length , op )
}
}
func LengthBetween ( val any , min , max int ) bool {
if ! Compare ( min , max , "<" ) {
panic ( ErrBadType )
} else if n , err := getLength ( val , false ) ; err != nil {
return false
} else {
return Compare ( n , min , ">=" ) && Compare ( n , max , "<=" )
}
}
// Compare intX,floatX value by given op. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
//
// Usage:
//
// compare(2, 3, ">") // false
// compare(2, 1.3, ">") // true
// compare(2.2, 1.3, ">") // true
// compare(2.1, 2, ">") // true
func Compare ( srcVal , dstVal any , op string ) bool {
srv := reflect . ValueOf ( srcVal )
switch srv . Kind ( ) {
case reflect . Struct :
if srv . Type ( ) . ConvertibleTo ( timeType ) {
drv := reflect . ValueOf ( dstVal )
if drv . Type ( ) . ConvertibleTo ( timeType ) {
at := srv . Convert ( timeType ) . Interface ( ) . ( time . Time )
bt := drv . Convert ( timeType ) . Interface ( ) . ( time . Time )
return compTime ( at , bt , op )
}
}
case reflect . Bool :
drv := reflect . ValueOf ( dstVal )
switch drv . Kind ( ) {
case reflect . Bool :
return compBool ( srv . Bool ( ) , drv . Bool ( ) , op )
case reflect . String :
if bl , err := strconv . ParseBool ( drv . String ( ) ) ; err == nil {
return compBool ( srv . Bool ( ) , bl , op )
}
}
default :
if srcStr , ok := srcVal . ( string ) ; ok {
if dstStr , ok2 := dstVal . ( string ) ; ok2 {
return compString ( srcStr , dstStr , op )
}
break
}
// float
if srcFlt , ok := srcVal . ( float64 ) ; ok {
if dstFlt , err := toFloat ( dstVal ) ; err == nil {
return compNum ( srcFlt , dstFlt , op )
}
break
}
if srcFlt , ok := srcVal . ( float32 ) ; ok {
if dstFlt , err := toFloat ( dstVal ) ; err == nil {
return compNum ( float64 ( srcFlt ) , dstFlt , op )
}
break
}
// as int64
if srcInt , err := toInt64 ( srcVal ) ; err != nil {
break
} else if dstInt , ex := toInt64 ( dstVal ) ; ex != nil {
break
} else {
return compNum ( srcInt , dstInt , op )
}
}
switch op {
case "=" :
return srcVal == dstVal
case "!=" :
return srcVal != dstVal
default :
//ErrBadType
return false
}
}
// GreaterThan is the validation function for validating if the current field's value is greater than the param's value.
func GreaterThan ( a , b any ) bool {
return Compare ( a , b , ">" )
}
// GreaterEqualThan is the validation function for validating if the current field's value is greater than or equal to the param's value.
func GreaterEqualThan ( a , b any ) bool {
return Compare ( a , b , ">=" )
}
// LessThan is the validation function for validating if the current field's value is less than the param's value.
func LessThan ( a , b any ) bool {
return Compare ( a , b , "<" )
}
// LessEqualThan is the validation function for validating if the current field's value is less than or equal to the param's value.
func LessEqualThan ( a , b any ) bool {
return Compare ( a , b , "<=" )
}
// Equal is the validation function for validating if the current field's value is equal to the param's value.
func Equal ( a , b any ) bool {
return Compare ( a , b , "=" )
}
func NotEqual ( a , b any ) bool {
return Compare ( a , b , "!=" )
}
func Between ( val , min , max any ) bool {
if ! Compare ( min , max , ">" ) {
panic ( ErrBadRange )
}
return Compare ( val , min , ">=" ) && Compare ( val , max , "<=" )
}
func NotBetween ( val , min , max any ) bool {
if ! Compare ( min , max , ">" ) {
panic ( ErrBadRange )
}
return Compare ( val , min , "<" ) || Compare ( val , max , ">" )
}