github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/validator_util.go (about)

     1  package f
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rsa"
     6  	"crypto/x509"
     7  	"encoding/base64"
     8  	"encoding/pem"
     9  	"errors"
    10  	"fmt"
    11  	json "github.com/json-iterator/go"
    12  	"html"
    13  	"io/ioutil"
    14  	"math"
    15  	"net"
    16  	"net/url"
    17  	"os"
    18  	"path"
    19  	"reflect"
    20  	"regexp"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  	"unicode"
    25  	"unicode/utf8"
    26  )
    27  
    28  // Contains asserts that the specified string, list(array, slice...) or map contains the
    29  // specified substring or element.
    30  //
    31  //    Contains("Hello World", "World")
    32  //    Contains(["Hello", "World"], "World")
    33  //    Contains({"Hello": "World"}, "Hello")
    34  func Contains(s, sub interface{}) bool {
    35  	ok, found := ContainsElement(s, sub)
    36  
    37  	// ok == false: 's' could not be applied builtin len()
    38  	// found == false: 's' does not contain 'sub'
    39  	return ok && found
    40  }
    41  
    42  // NotContains check that the specified string, list(array, slice) or map does NOT contain the
    43  // specified substring or element.
    44  //
    45  // Notice: list check value exist. map check key exist.
    46  func NotContains(s, sub interface{}) bool {
    47  	ok, found := ContainsElement(s, sub)
    48  
    49  	// ok == false: could not be applied builtin len()
    50  	// found == true: 's' contain 'sub'
    51  	return ok && !found
    52  }
    53  
    54  // ContainsElement from package: github.com/stretchr/testify/assert/assertions.go
    55  func ContainsElement(list, element interface{}) (ok, found bool) {
    56  	listValue := reflect.ValueOf(list)
    57  	listKind := reflect.TypeOf(list).Kind()
    58  	defer func() {
    59  		if e := recover(); e != nil {
    60  			ok = false
    61  			found = false
    62  		}
    63  	}()
    64  
    65  	if listKind == reflect.String {
    66  		elementValue := reflect.ValueOf(element)
    67  		return true, strings.Contains(listValue.String(), elementValue.String())
    68  	}
    69  
    70  	if listKind == reflect.Map {
    71  		mapKeys := listValue.MapKeys()
    72  		for i := 0; i < len(mapKeys); i++ {
    73  			if IsEqual(mapKeys[i].Interface(), element) {
    74  				return true, true
    75  			}
    76  		}
    77  		return true, false
    78  	}
    79  
    80  	for i := 0; i < listValue.Len(); i++ {
    81  		if IsEqual(listValue.Index(i).Interface(), element) {
    82  			return true, true
    83  		}
    84  	}
    85  	return true, false
    86  }
    87  
    88  // Matches checks if string matches the pattern (pattern is regular expression)
    89  // In case of error return false
    90  func Matches(str, pattern string) bool {
    91  	match, _ := regexp.MatchString(pattern, str)
    92  	return match
    93  }
    94  
    95  // LeftTrim trims characters from the left side of the input.
    96  // If second argument is empty, it will remove leading spaces.
    97  func LeftTrim(str, chars string) string {
    98  	if chars == "" {
    99  		return strings.TrimLeftFunc(str, unicode.IsSpace)
   100  	}
   101  	r, _ := regexp.Compile("^[" + chars + "]+")
   102  	return r.ReplaceAllString(str, "")
   103  }
   104  
   105  // RightTrim trims characters from the right side of the input.
   106  // If second argument is empty, it will remove trailing spaces.
   107  func RightTrim(str, chars string) string {
   108  	if chars == "" {
   109  		return strings.TrimRightFunc(str, unicode.IsSpace)
   110  	}
   111  	r, _ := regexp.Compile("[" + chars + "]+$")
   112  	return r.ReplaceAllString(str, "")
   113  }
   114  
   115  // Trim trims characters from both sides of the input.
   116  // If second argument is empty, it will remove spaces.
   117  func Trim(str, chars string) string {
   118  	return LeftTrim(RightTrim(str, chars), chars)
   119  }
   120  
   121  // WhiteList removes characters that do not appear in the whitelist.
   122  func WhiteList(str, chars string) string {
   123  	pattern := "[^" + chars + "]+"
   124  	r, _ := regexp.Compile(pattern)
   125  	return r.ReplaceAllString(str, "")
   126  }
   127  
   128  // BlackList removes characters that appear in the blacklist.
   129  func BlackList(str, chars string) string {
   130  	pattern := "[" + chars + "]+"
   131  	r, _ := regexp.Compile(pattern)
   132  	return r.ReplaceAllString(str, "")
   133  }
   134  
   135  // StripLow removes characters with a numerical value < 32 and 127, mostly control characters.
   136  // If keep_new_lines is true, newline characters are preserved (\n and \r, hex 0xA and 0xD).
   137  func StripLow(str string, keepNewLines bool) string {
   138  	chars := ""
   139  	if keepNewLines {
   140  		chars = "\x00-\x09\x0B\x0C\x0E-\x1F\x7F"
   141  	} else {
   142  		chars = "\x00-\x1F\x7F"
   143  	}
   144  	return BlackList(str, chars)
   145  }
   146  
   147  // ReplacePattern replaces regular expression pattern in string
   148  func ReplacePattern(str, pattern, replace string) string {
   149  	r, _ := regexp.Compile(pattern)
   150  	return r.ReplaceAllString(str, replace)
   151  }
   152  
   153  // Escape replaces <, >, & and " with HTML entities.
   154  var Escape = html.EscapeString
   155  
   156  func addSegment(inrune, segment []rune) []rune {
   157  	if len(segment) == 0 {
   158  		return inrune
   159  	}
   160  	if len(inrune) != 0 {
   161  		inrune = append(inrune, '_')
   162  	}
   163  	inrune = append(inrune, segment...)
   164  	return inrune
   165  }
   166  
   167  // UnderscoreToCamelCase converts from underscore separated form to camel case form.
   168  // Ex.: my_func => MyFunc
   169  func UnderscoreToCamelCase(s string) string {
   170  	return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
   171  }
   172  
   173  // CamelCaseToUnderscore converts from camel case form to underscore separated form.
   174  // Ex.: MyFunc => my_func
   175  func CamelCaseToUnderscore(str string) string {
   176  	var output []rune
   177  	var segment []rune
   178  	for _, r := range str {
   179  
   180  		// not treat number as separate segment
   181  		if !unicode.IsLower(r) && string(r) != "_" && !unicode.IsNumber(r) {
   182  			output = addSegment(output, segment)
   183  			segment = nil
   184  		}
   185  		segment = append(segment, unicode.ToLower(r))
   186  	}
   187  	output = addSegment(output, segment)
   188  	return string(output)
   189  }
   190  
   191  // Reverse returns reversed string
   192  func Reverse(s string) string {
   193  	r := []rune(s)
   194  	for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
   195  		r[i], r[j] = r[j], r[i]
   196  	}
   197  	return string(r)
   198  }
   199  
   200  // GetLines splits string by "\n" and return array of lines
   201  func GetLines(s string) []string {
   202  	return strings.Split(s, "\n")
   203  }
   204  
   205  // GetLine returns specified line of multiline string
   206  func GetLine(s string, index int) (string, error) {
   207  	lines := GetLines(s)
   208  	if index < 0 || index >= len(lines) {
   209  		return "", errors.New("line index out of bounds")
   210  	}
   211  	return lines[index], nil
   212  }
   213  
   214  // RemoveTags removes all tags from HTML string
   215  func RemoveTags(s string) string {
   216  	return ReplacePattern(s, "<[^>]*>", "")
   217  }
   218  
   219  // SafeFileName returns safe string that can be used in file names
   220  func SafeFileName(str string) string {
   221  	name := strings.ToLower(str)
   222  	name = path.Clean(path.Base(name))
   223  	name = strings.Trim(name, " ")
   224  	separators, err := regexp.Compile(`[ &_=+:]`)
   225  	if err == nil {
   226  		name = separators.ReplaceAllString(name, "-")
   227  	}
   228  	legal, err := regexp.Compile(`[^[:alnum:]-.]`)
   229  	if err == nil {
   230  		name = legal.ReplaceAllString(name, "")
   231  	}
   232  	for strings.Contains(name, "--") {
   233  		name = strings.Replace(name, "--", "-", -1)
   234  	}
   235  	return name
   236  }
   237  
   238  // NormalizeEmail canonicalize an email address.
   239  // The local part of the email address is lowercased for all domains; the hostname is always lowercased and
   240  // the local part of the email address is always lowercased for hosts that are known to be case-insensitive (currently only GMail).
   241  // Normalization follows special rules for known providers: currently, GMail addresses have dots removed in the local part and
   242  // are stripped of tags (e.g. some.one+tag@gmail.com becomes someone@gmail.com) and all @googlemail.com addresses are
   243  // normalized to @gmail.com.
   244  func NormalizeEmail(str string) (string, error) {
   245  	if !IsEmail(str) {
   246  		return "", fmt.Errorf("%s is not an email", str)
   247  	}
   248  	parts := strings.Split(str, "@")
   249  	parts[0] = strings.ToLower(parts[0])
   250  	parts[1] = strings.ToLower(parts[1])
   251  	if parts[1] == "gmail.com" || parts[1] == "googlemail.com" {
   252  		parts[1] = "gmail.com"
   253  		parts[0] = strings.Split(ReplacePattern(parts[0], `\.`, ""), "+")[0]
   254  	}
   255  	return strings.Join(parts, "@"), nil
   256  }
   257  
   258  // Truncate a string to the closest length without breaking words.
   259  func Truncate(str string, length int, ending string) string {
   260  	var aftstr, befstr string
   261  	if len(str) > length {
   262  		words := strings.Fields(str)
   263  		before, present := 0, 0
   264  		for i := range words {
   265  			befstr = aftstr
   266  			before = present
   267  			aftstr = aftstr + words[i] + " "
   268  			present = len(aftstr)
   269  			if present > length && i != 0 {
   270  				if (length - before) < (present - length) {
   271  					return Trim(befstr, " /\\.,\"'#!?&@+-") + ending
   272  				}
   273  				return Trim(aftstr, " /\\.,\"'#!?&@+-") + ending
   274  			}
   275  		}
   276  	}
   277  
   278  	return str
   279  }
   280  
   281  // PadLeft pads left side of a string if size of string is less then indicated pad length
   282  func PadLeft(str string, padStr string, padLen int) string {
   283  	return buildPadStr(str, padStr, padLen, true, false)
   284  }
   285  
   286  // PadRight pads right side of a string if size of string is less then indicated pad length
   287  func PadRight(str string, padStr string, padLen int) string {
   288  	return buildPadStr(str, padStr, padLen, false, true)
   289  }
   290  
   291  // PadBoth pads both sides of a string if size of string is less then indicated pad length
   292  func PadBoth(str string, padStr string, padLen int) string {
   293  	return buildPadStr(str, padStr, padLen, true, true)
   294  }
   295  
   296  // PadString either left, right or both sides.
   297  // Note that padding string can be unicode and more then one character
   298  func buildPadStr(str string, padStr string, padLen int, padLeft bool, padRight bool) string {
   299  
   300  	// When padded length is less then the current string size
   301  	if padLen < utf8.RuneCountInString(str) {
   302  		return str
   303  	}
   304  
   305  	padLen -= utf8.RuneCountInString(str)
   306  
   307  	targetLen := padLen
   308  
   309  	targetLenLeft := targetLen
   310  	targetLenRight := targetLen
   311  	if padLeft && padRight {
   312  		targetLenLeft = padLen / 2
   313  		targetLenRight = padLen - targetLenLeft
   314  	}
   315  
   316  	strToRepeatLen := utf8.RuneCountInString(padStr)
   317  
   318  	repeatTimes := int(math.Ceil(float64(targetLen) / float64(strToRepeatLen)))
   319  	repeatedString := strings.Repeat(padStr, repeatTimes)
   320  
   321  	leftSide := ""
   322  	if padLeft {
   323  		leftSide = repeatedString[0:targetLenLeft]
   324  	}
   325  
   326  	rightSide := ""
   327  	if padRight {
   328  		rightSide = repeatedString[0:targetLenRight]
   329  	}
   330  
   331  	return leftSide + str + rightSide
   332  }
   333  
   334  // TruncatingErrorf removes extra args from fmt.Errorf if not formatted in the str object
   335  func TruncatingErrorf(str string, args ...interface{}) error {
   336  	n := strings.Count(str, "%s")
   337  	return fmt.Errorf(str, args[:n]...)
   338  }
   339  
   340  // IsUint check, allow: intX, uintX, string
   341  func IsUint(val interface{}) bool {
   342  	switch typVal := val.(type) {
   343  	case int:
   344  		return typVal >= 0
   345  	case int8:
   346  		return typVal >= 0
   347  	case int16:
   348  		return typVal >= 0
   349  	case int32:
   350  		return typVal >= 0
   351  	case int64:
   352  		return typVal >= 0
   353  	case uint, uint8, uint16, uint32, uint64:
   354  		return true
   355  	case string:
   356  		_, err := strconv.ParseUint(typVal, 10, 32)
   357  		return err == nil
   358  	}
   359  	return false
   360  }
   361  
   362  // IsBool check. allow: bool, string.
   363  func IsBool(val interface{}) bool {
   364  	if _, ok := val.(bool); ok {
   365  		return true
   366  	}
   367  
   368  	if typVal, ok := val.(string); ok {
   369  		_, err := ToBool(typVal)
   370  		return err == nil
   371  	}
   372  	return false
   373  }
   374  
   375  // IsFloat check if the string is a float.
   376  func IsFloat(str string) bool {
   377  	return str != "" && rxFloat.MatchString(str)
   378  }
   379  
   380  // IsArray check
   381  func IsArray(val interface{}) bool {
   382  	if val == nil {
   383  		return false
   384  	}
   385  
   386  	rv := reflect.ValueOf(val)
   387  	if rv.Kind() == reflect.Ptr {
   388  		rv = rv.Elem()
   389  	}
   390  	return rv.Kind() == reflect.Array
   391  }
   392  
   393  // IsSlice check
   394  func IsSlice(val interface{}) bool {
   395  	if val == nil {
   396  		return false
   397  	}
   398  
   399  	rv := reflect.ValueOf(val)
   400  	if rv.Kind() == reflect.Ptr {
   401  		rv = rv.Elem()
   402  	}
   403  	return rv.Kind() == reflect.Slice
   404  }
   405  
   406  // IsIntSlice is int slice check
   407  func IsIntSlice(val interface{}) bool {
   408  	if val == nil {
   409  		return false
   410  	}
   411  
   412  	switch val.(type) {
   413  	case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64:
   414  		return true
   415  	}
   416  	return false
   417  }
   418  
   419  // IsStrings is string slice check
   420  func IsStrings(val interface{}) bool {
   421  	if val == nil {
   422  		return false
   423  	}
   424  
   425  	if _, ok := val.([]string); ok {
   426  		return true
   427  	}
   428  	//if _, ok := val.(g.Strings); ok {
   429  	//	return true
   430  	//}
   431  	return false
   432  }
   433  
   434  // IsMap check
   435  func IsMap(val interface{}) (ok bool) {
   436  	if val == nil {
   437  		return false
   438  	}
   439  
   440  	//if _, ok = val.(g.Map); ok {
   441  	//	return true
   442  	//}
   443  	var rv reflect.Value
   444  	if rv, ok = val.(reflect.Value); !ok {
   445  		rv = reflect.ValueOf(val)
   446  	}
   447  
   448  	if rv.Kind() == reflect.Ptr {
   449  		rv = rv.Elem()
   450  	}
   451  
   452  	return rv.Kind() == reflect.Map
   453  }
   454  
   455  // IsInt check if the string is an integer. Empty string is not valid.
   456  func IsInt(str string) bool {
   457  	if IsNull(str) {
   458  		return false
   459  	}
   460  	return rxInt.MatchString(str)
   461  }
   462  
   463  // IsInt check, and support length check
   464  func IsInt2(val interface{}, minAndMax ...int64) (ok bool) {
   465  	if val == nil {
   466  		return false
   467  	}
   468  
   469  	intVal, err := ToInt(val)
   470  	if err != nil {
   471  		return false
   472  	}
   473  
   474  	argLn := len(minAndMax)
   475  	if argLn == 0 { // only check type
   476  		return true
   477  	}
   478  
   479  	// value check
   480  	minVal := minAndMax[0]
   481  	if argLn == 1 { // only min length check.
   482  		return intVal >= minVal
   483  	}
   484  
   485  	maxVal := minAndMax[1]
   486  
   487  	// min and max length check
   488  	return intVal >= minVal && intVal <= maxVal
   489  }
   490  
   491  // IsString check and support length check.
   492  // Usage:
   493  // 	ok := IsString(val)
   494  // 	ok := IsString(val, 5) // with min len check
   495  // 	ok := IsString(val, 5, 12) // with min and max len check
   496  func IsString(val interface{}, minAndMaxLen ...int) (ok bool) {
   497  	if val == nil {
   498  		return false
   499  	}
   500  
   501  	argLn := len(minAndMaxLen)
   502  	str, isStr := val.(string)
   503  
   504  	// only check type
   505  	if argLn == 0 {
   506  		return isStr
   507  	}
   508  
   509  	if !isStr {
   510  		return false
   511  	}
   512  
   513  	// length check
   514  	strLen := len(str)
   515  	minLen := minAndMaxLen[0]
   516  
   517  	// only min length check.
   518  	if argLn == 1 {
   519  		return strLen >= minLen
   520  	}
   521  
   522  	// min and max length check
   523  	maxLen := minAndMaxLen[1]
   524  	return strLen >= minLen && strLen <= maxLen
   525  }
   526  
   527  /*************************************************************
   528   * global: string validators
   529   *************************************************************/
   530  
   531  // HasWhitespace checks if the string contains any whitespace
   532  func HasWhitespace(str string) bool {
   533  	return len(str) > 0 && rxHasWhitespace.MatchString(str)
   534  }
   535  
   536  // HasWhitespace check. eg "10"
   537  func HasWhitespace2(s string) bool {
   538  	return s != "" && strings.ContainsRune(s, ' ')
   539  }
   540  
   541  // IsIntString check. eg "10"
   542  func IsIntString(s string) bool {
   543  	return s != "" && rxInt.MatchString(s)
   544  }
   545  
   546  // IsASCII check if the string contains ASCII chars only. Empty string is valid.
   547  func IsASCII(str string) bool {
   548  	if IsNull(str) {
   549  		return true
   550  	}
   551  	return rxASCII.MatchString(str)
   552  }
   553  
   554  // IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid.
   555  func IsPrintableASCII(str string) bool {
   556  	if IsNull(str) {
   557  		return true
   558  	}
   559  	return rxPrintableASCII.MatchString(str)
   560  }
   561  
   562  // IsFullWidth check if the string contains any full-width chars. Empty string is valid.
   563  func IsFullWidth(str string) bool {
   564  	if IsNull(str) {
   565  		return true
   566  	}
   567  	return rxFullWidth.MatchString(str)
   568  }
   569  
   570  // IsHalfWidth check if the string contains any half-width chars. Empty string is valid.
   571  func IsHalfWidth(str string) bool {
   572  	if IsNull(str) {
   573  		return true
   574  	}
   575  	return rxHalfWidth.MatchString(str)
   576  }
   577  
   578  // IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid.
   579  func IsVariableWidth(str string) bool {
   580  	if IsNull(str) {
   581  		return true
   582  	}
   583  	return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str)
   584  }
   585  
   586  // IsBase64 check if a string is base64 encoded.
   587  func IsBase64(s string) bool {
   588  	return s != "" && rxBase64.MatchString(s)
   589  }
   590  
   591  // IsLatitude check if a string is valid latitude.
   592  func IsLatitude(s string) bool {
   593  	return s != "" && rxLatitude.MatchString(s)
   594  }
   595  
   596  // IsLongitude check if a string is valid longitude.
   597  func IsLongitude(s string) bool {
   598  	return s != "" && rxLongitude.MatchString(s)
   599  }
   600  
   601  // IsIMEI check if a string is valid IMEI
   602  func IsIMEI(str string) bool {
   603  	return rxIMEI.MatchString(str)
   604  }
   605  
   606  // IsRsaPublicKey check if a string is valid public key with provided length
   607  func IsRsaPublicKey(str string, keylen int) bool {
   608  	bb := bytes.NewBufferString(str)
   609  	pemBytes, err := ioutil.ReadAll(bb)
   610  	if err != nil {
   611  		return false
   612  	}
   613  	block, _ := pem.Decode(pemBytes)
   614  	if block != nil && block.Type != "PUBLIC KEY" {
   615  		return false
   616  	}
   617  	var der []byte
   618  
   619  	if block != nil {
   620  		der = block.Bytes
   621  	} else {
   622  		der, err = base64.StdEncoding.DecodeString(str)
   623  		if err != nil {
   624  			return false
   625  		}
   626  	}
   627  
   628  	key, err := x509.ParsePKIXPublicKey(der)
   629  	if err != nil {
   630  		return false
   631  	}
   632  	pubkey, ok := key.(*rsa.PublicKey)
   633  	if !ok {
   634  		return false
   635  	}
   636  	bitlen := len(pubkey.N.Bytes()) * 8
   637  	return bitlen == int(keylen)
   638  }
   639  
   640  func toJSONName(tag string) string {
   641  	if tag == "" {
   642  		return ""
   643  	}
   644  
   645  	// JSON name always comes first. If there's no options then split[0] is
   646  	// JSON name, if JSON name is not set, then split[0] is an empty string.
   647  	split := strings.SplitN(tag, ",", 2)
   648  
   649  	name := split[0]
   650  
   651  	// However it is possible that the field is skipped when
   652  	// (de-)serializing from/to JSON, in which case assume that there is no
   653  	// tag name to use
   654  	if name == "-" {
   655  		return ""
   656  	}
   657  	return name
   658  }
   659  
   660  func PrependPathToErrors(err error, path string) error {
   661  	switch err2 := err.(type) {
   662  	case Error:
   663  		err2.Path = append([]string{path}, err2.Path...)
   664  		return err2
   665  	case Errors:
   666  		errors := err2.Errors()
   667  		for i, err3 := range errors {
   668  			errors[i] = PrependPathToErrors(err3, path)
   669  		}
   670  		return err2
   671  	}
   672  	return err
   673  }
   674  
   675  // IsHash checks if a string is a hash of type algorithm.
   676  // Algorithm is one of ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
   677  func IsHash(str string, algorithm string) bool {
   678  	len := "0"
   679  	algo := strings.ToLower(algorithm)
   680  
   681  	if algo == "crc32" || algo == "crc32b" {
   682  		len = "8"
   683  	} else if algo == "md5" || algo == "md4" || algo == "ripemd128" || algo == "tiger128" {
   684  		len = "32"
   685  	} else if algo == "sha1" || algo == "ripemd160" || algo == "tiger160" {
   686  		len = "40"
   687  	} else if algo == "tiger192" {
   688  		len = "48"
   689  	} else if algo == "sha256" {
   690  		len = "64"
   691  	} else if algo == "sha384" {
   692  		len = "96"
   693  	} else if algo == "sha512" {
   694  		len = "128"
   695  	} else {
   696  		return false
   697  	}
   698  
   699  	return Matches(str, "^[a-f0-9]{"+len+"}$")
   700  }
   701  
   702  // IsSHA512 checks is a string is a SHA512 hash. Alias for `IsHash(str, "sha512")`
   703  func IsSHA512(str string) bool {
   704  	return IsHash(str, "sha512")
   705  }
   706  
   707  // IsSHA384 checks is a string is a SHA384 hash. Alias for `IsHash(str, "sha384")`
   708  func IsSHA384(str string) bool {
   709  	return IsHash(str, "sha384")
   710  }
   711  
   712  // IsSHA256 checks is a string is a SHA256 hash. Alias for `IsHash(str, "sha256")`
   713  func IsSHA256(str string) bool {
   714  	return IsHash(str, "sha256")
   715  }
   716  
   717  // IsTiger192 checks is a string is a Tiger192 hash. Alias for `IsHash(str, "tiger192")`
   718  func IsTiger192(str string) bool {
   719  	return IsHash(str, "tiger192")
   720  }
   721  
   722  // IsTiger160 checks is a string is a Tiger160 hash. Alias for `IsHash(str, "tiger160")`
   723  func IsTiger160(str string) bool {
   724  	return IsHash(str, "tiger160")
   725  }
   726  
   727  // IsRipeMD160 checks is a string is a RipeMD160 hash. Alias for `IsHash(str, "ripemd160")`
   728  func IsRipeMD160(str string) bool {
   729  	return IsHash(str, "ripemd160")
   730  }
   731  
   732  // IsSHA1 checks is a string is a SHA-1 hash. Alias for `IsHash(str, "sha1")`
   733  func IsSHA1(str string) bool {
   734  	return IsHash(str, "sha1")
   735  }
   736  
   737  // IsTiger128 checks is a string is a Tiger128 hash. Alias for `IsHash(str, "tiger128")`
   738  func IsTiger128(str string) bool {
   739  	return IsHash(str, "tiger128")
   740  }
   741  
   742  // IsRipeMD128 checks is a string is a RipeMD128 hash. Alias for `IsHash(str, "ripemd128")`
   743  func IsRipeMD128(str string) bool {
   744  	return IsHash(str, "ripemd128")
   745  }
   746  
   747  // IsCRC32 checks is a string is a CRC32 hash. Alias for `IsHash(str, "crc32")`
   748  func IsCRC32(str string) bool {
   749  	return IsHash(str, "crc32")
   750  }
   751  
   752  // IsCRC32b checks is a string is a CRC32b hash. Alias for `IsHash(str, "crc32b")`
   753  func IsCRC32b(str string) bool {
   754  	return IsHash(str, "crc32b")
   755  }
   756  
   757  // IsMD5 checks is a string is a MD5 hash. Alias for `IsHash(str, "md5")`
   758  func IsMD5(str string) bool {
   759  	return IsHash(str, "md5")
   760  }
   761  
   762  // IsMD4 checks is a string is a MD4 hash. Alias for `IsHash(str, "md4")`
   763  func IsMD4(str string) bool {
   764  	return IsHash(str, "md4")
   765  }
   766  
   767  // IsDialString validates the given string for usage with the various Dial() functions
   768  func IsDialString(str string) bool {
   769  	if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) {
   770  		return true
   771  	}
   772  
   773  	return false
   774  }
   775  
   776  // IsDNSName will validate the given string as a DNS name
   777  func IsDNSName(str string) bool {
   778  	if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
   779  		// constraints already violated
   780  		return false
   781  	}
   782  	return !IsIP(str) && rxDNSName.MatchString(str)
   783  }
   784  
   785  // HasURLSchema string.
   786  func HasURLSchema(s string) bool {
   787  	return s != "" && rxURLSchema.MatchString(s)
   788  }
   789  
   790  // IsRequestURL check if the string rawurl, assuming
   791  // it was received in an HTTP request, is a valid
   792  // URL confirm to RFC 3986
   793  func IsRequestURL(s string) bool {
   794  	u, err := url.ParseRequestURI(s)
   795  	if err != nil {
   796  		return false //Couldn't even parse the rawurl
   797  	}
   798  	if len(u.Scheme) == 0 {
   799  		return false //No Scheme found
   800  	}
   801  	return true
   802  }
   803  
   804  // IsRequestURI check if the string rawurl, assuming
   805  // it was received in an HTTP request, is an
   806  // absolute URI or an absolute path.
   807  func IsRequestURI(s string) bool {
   808  	_, err := url.ParseRequestURI(s)
   809  	return err == nil
   810  }
   811  
   812  // IsFullURL string.
   813  func IsFullURL(s string) bool {
   814  	return s != "" && rxFullURL.MatchString(s)
   815  }
   816  
   817  // IsURL check if the string is an URL.
   818  func IsURL(str string) bool {
   819  	if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") {
   820  		return false
   821  	}
   822  	strTemp := str
   823  	if strings.Contains(str, ":") && !strings.Contains(str, "://") {
   824  		// support no indicated urlscheme but with colon for port number
   825  		// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
   826  		strTemp = "http://" + str
   827  	}
   828  	u, err := url.Parse(strTemp)
   829  	if err != nil {
   830  		return false
   831  	}
   832  	if strings.HasPrefix(u.Host, ".") {
   833  		return false
   834  	}
   835  	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
   836  		return false
   837  	}
   838  	return rxURL.MatchString(str)
   839  }
   840  
   841  // IsDataURI checks if a string is base64 encoded data URI such as an image
   842  func IsDataURI(str string) bool {
   843  	dataURI := strings.Split(str, ",")
   844  	if !rxDataURI.MatchString(dataURI[0]) {
   845  		return false
   846  	}
   847  	return IsBase64(dataURI[1])
   848  }
   849  
   850  // IsMagnetURI checks if a string is valid magnet URI
   851  func IsMagnetURI(str string) bool {
   852  	return rxMagnetURI.MatchString(str)
   853  }
   854  
   855  // IsISO3166Alpha2 checks if a string is valid two-letter country code
   856  func IsISO3166Alpha2(str string) bool {
   857  	for _, entry := range ISO3166List {
   858  		if str == entry.Alpha2Code {
   859  			return true
   860  		}
   861  	}
   862  	return false
   863  }
   864  
   865  // IsISO3166Alpha3 checks if a string is valid three-letter country code
   866  func IsISO3166Alpha3(str string) bool {
   867  	for _, entry := range ISO3166List {
   868  		if str == entry.Alpha3Code {
   869  			return true
   870  		}
   871  	}
   872  	return false
   873  }
   874  
   875  // IsISO693Alpha2 checks if a string is valid two-letter language code
   876  func IsISO693Alpha2(str string) bool {
   877  	for _, entry := range ISO693List {
   878  		if str == entry.Alpha2Code {
   879  			return true
   880  		}
   881  	}
   882  	return false
   883  }
   884  
   885  // IsISO693Alpha3b checks if a string is valid three-letter language code
   886  func IsISO693Alpha3b(str string) bool {
   887  	for _, entry := range ISO693List {
   888  		if str == entry.Alpha3bCode {
   889  			return true
   890  		}
   891  	}
   892  	return false
   893  }
   894  
   895  // IsMultiByte check if the string contains one or more multibyte chars. Empty string is valid.
   896  func IsMultiByte(s string) bool {
   897  	if IsNull(s) {
   898  		return true
   899  	}
   900  	return s != "" && rxMultiByte.MatchString(s)
   901  }
   902  
   903  // IsISBN10 string.
   904  func IsISBN10(s string) bool {
   905  	return s != "" && IsISBN(s, 10)
   906  }
   907  
   908  // IsISBN13 string.
   909  func IsISBN13(s string) bool {
   910  	return s != "" && IsISBN(s, 13)
   911  }
   912  
   913  // IsISBN check if the string is an ISBN (version 10 or 13).
   914  // If version value is not equal to 10 or 13, it will be check both variants.
   915  func IsISBN(str string, version int) bool {
   916  	sanitized := whiteSpacesAndMinus.ReplaceAllString(str, "")
   917  	var checksum int32
   918  	var i int32
   919  	if version == 10 {
   920  		if !rxISBN10.MatchString(sanitized) {
   921  			return false
   922  		}
   923  		for i = 0; i < 9; i++ {
   924  			checksum += (i + 1) * int32(sanitized[i]-'0')
   925  		}
   926  		if sanitized[9] == 'X' {
   927  			checksum += 10 * 10
   928  		} else {
   929  			checksum += 10 * int32(sanitized[9]-'0')
   930  		}
   931  		if checksum%11 == 0 {
   932  			return true
   933  		}
   934  		return false
   935  	} else if version == 13 {
   936  		if !rxISBN13.MatchString(sanitized) {
   937  			return false
   938  		}
   939  		factor := []int32{1, 3}
   940  		for i = 0; i < 12; i++ {
   941  			checksum += factor[i%2] * int32(sanitized[i]-'0')
   942  		}
   943  		return (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0
   944  	}
   945  	return IsISBN(str, 10) || IsISBN(str, 13)
   946  }
   947  
   948  // IsHexadecimal check if the string is a hexadecimal number.
   949  func IsHexadecimal(s string) bool {
   950  	return s != "" && rxHexadecimal.MatchString(s)
   951  }
   952  
   953  // IsCnMobile string.
   954  func IsCnMobile(s string) bool {
   955  	return s != "" && rxCnMobile.MatchString(s)
   956  }
   957  
   958  // IsHexColor string.
   959  func IsHexColor(s string) bool {
   960  	return s != "" && rxHexColor.MatchString(s)
   961  }
   962  
   963  // IsRGBColor string.
   964  func IsRGBColor(s string) bool {
   965  	return s != "" && rxRGBColor.MatchString(s)
   966  }
   967  
   968  // IsLowerCase check if the string is lowercase. Empty string is valid.
   969  func IsLowerCase(str string) bool {
   970  	if IsNull(str) {
   971  		return true
   972  	}
   973  	return str == strings.ToLower(str)
   974  }
   975  
   976  // IsUpperCase check if the string is uppercase. Empty string is valid.
   977  func IsUpperCase(str string) bool {
   978  	if IsNull(str) {
   979  		return true
   980  	}
   981  	return str == strings.ToUpper(str)
   982  }
   983  
   984  //IsUTFLetter check if the string contains only unicode letter characters.
   985  //Similar to IsAlpha but for all languages. Empty string is valid.
   986  func IsUTFLetter(str string) bool {
   987  	if IsNull(str) {
   988  		return true
   989  	}
   990  
   991  	for _, c := range str {
   992  		if !unicode.IsLetter(c) {
   993  			return false
   994  		}
   995  	}
   996  	return true
   997  
   998  }
   999  
  1000  // IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid.
  1001  func IsAlphanumeric(str string) bool {
  1002  	if IsNull(str) {
  1003  		return true
  1004  	}
  1005  	return rxAlphaNumeric.MatchString(str)
  1006  }
  1007  
  1008  // IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid.
  1009  func IsUTFLetterNumeric(str string) bool {
  1010  	if IsNull(str) {
  1011  		return true
  1012  	}
  1013  	for _, c := range str {
  1014  		if !unicode.IsLetter(c) && !unicode.IsNumber(c) { //letters && numbers are ok
  1015  			return false
  1016  		}
  1017  	}
  1018  	return true
  1019  }
  1020  
  1021  // IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid.
  1022  func IsAlpha(str string) bool {
  1023  	if IsNull(str) {
  1024  		return true
  1025  	}
  1026  	return rxAlpha.MatchString(str)
  1027  }
  1028  
  1029  // IsAlphaNum string.
  1030  func IsAlphaNum(s string) bool {
  1031  	return s != "" && rxAlphaNumeric.MatchString(s)
  1032  }
  1033  
  1034  // IsAlphaDash string.
  1035  func IsAlphaDash(s string) bool {
  1036  	return s != "" && rxAlphaDash.MatchString(s)
  1037  }
  1038  
  1039  // IsNumber string. should >= 0
  1040  func IsNumber(v interface{}) bool {
  1041  	return rxNumeric.MatchString(ToString(v))
  1042  }
  1043  
  1044  // IsNumeric check if the string contains only numbers. Empty string is valid.
  1045  func IsNumeric(str string) bool {
  1046  	if IsNull(str) {
  1047  		return true
  1048  	}
  1049  	return rxNumeric.MatchString(str)
  1050  }
  1051  
  1052  // IsStringNumber is string number. should >= 0
  1053  func IsStringNumber(s string) bool {
  1054  	return s != "" && rxNumeric.MatchString(s)
  1055  }
  1056  
  1057  // IsUTFNumeric check if the string contains only unicode numbers of any kind.
  1058  // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid.
  1059  func IsUTFNumeric(str string) bool {
  1060  	if IsNull(str) {
  1061  		return true
  1062  	}
  1063  	if strings.IndexAny(str, "+-") > 0 {
  1064  		return false
  1065  	}
  1066  	if len(str) > 1 {
  1067  		str = strings.TrimPrefix(str, "-")
  1068  		str = strings.TrimPrefix(str, "+")
  1069  	}
  1070  	for _, c := range str {
  1071  		if !unicode.IsNumber(c) { //numbers && minus sign are ok
  1072  			return false
  1073  		}
  1074  	}
  1075  	return true
  1076  }
  1077  
  1078  // IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid.
  1079  func IsUTFDigit(str string) bool {
  1080  	if IsNull(str) {
  1081  		return true
  1082  	}
  1083  	if strings.IndexAny(str, "+-") > 0 {
  1084  		return false
  1085  	}
  1086  	if len(str) > 1 {
  1087  		str = strings.TrimPrefix(str, "-")
  1088  		str = strings.TrimPrefix(str, "+")
  1089  	}
  1090  	for _, c := range str {
  1091  		if !unicode.IsDigit(c) { //digits && minus sign are ok
  1092  			return false
  1093  		}
  1094  	}
  1095  	return true
  1096  
  1097  }
  1098  
  1099  // IsEmail check if the string is an email.
  1100  func IsEmail(s string) bool {
  1101  	return s != "" && rxEmail.MatchString(s)
  1102  }
  1103  
  1104  // IsExistingEmail check if the string is an email of existing domain
  1105  func IsExistingEmail(email string) bool {
  1106  
  1107  	if len(email) < 6 || len(email) > 254 {
  1108  		return false
  1109  	}
  1110  	at := strings.LastIndex(email, "@")
  1111  	if at <= 0 || at > len(email)-3 {
  1112  		return false
  1113  	}
  1114  	user := email[:at]
  1115  	host := email[at+1:]
  1116  	if len(user) > 64 {
  1117  		return false
  1118  	}
  1119  	if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
  1120  		return false
  1121  	}
  1122  	switch host {
  1123  	case "localhost", "example.com":
  1124  		return true
  1125  	}
  1126  	if _, err := net.LookupMX(host); err != nil {
  1127  		if _, err := net.LookupIP(host); err != nil {
  1128  			return false
  1129  		}
  1130  	}
  1131  
  1132  	return true
  1133  }
  1134  
  1135  // IsByteLength check if the string's length (in bytes) falls in a range.
  1136  func IsByteLength(str string, min, max int) bool {
  1137  	return len(str) >= min && len(str) <= max
  1138  }
  1139  
  1140  // IsUUIDv3 check if the string is a UUID version 3.
  1141  func IsUUIDv3(str string) bool {
  1142  	return rxUUID3.MatchString(str)
  1143  }
  1144  
  1145  // IsUUIDv4 check if the string is a UUID version 4.
  1146  func IsUUIDv4(str string) bool {
  1147  	return rxUUID4.MatchString(str)
  1148  }
  1149  
  1150  // IsUUIDv5 check if the string is a UUID version 5.
  1151  func IsUUIDv5(str string) bool {
  1152  	return rxUUID5.MatchString(str)
  1153  }
  1154  
  1155  // IsUUID check if the string is a UUID (version 3, 4 or 5).
  1156  func IsUUID(s string) bool {
  1157  	return s != "" && rxUUID.MatchString(s)
  1158  }
  1159  
  1160  // IsUUID3 string
  1161  func IsUUID3(s string) bool {
  1162  	return s != "" && rxUUID3.MatchString(s)
  1163  }
  1164  
  1165  // IsUUID4 string
  1166  func IsUUID4(s string) bool {
  1167  	return s != "" && rxUUID4.MatchString(s)
  1168  }
  1169  
  1170  // IsUUID5 string
  1171  func IsUUID5(s string) bool {
  1172  	return s != "" && rxUUID5.MatchString(s)
  1173  }
  1174  
  1175  // IsCreditCard check if the string is a credit card.
  1176  func IsCreditCard(str string) bool {
  1177  	sanitized := notNumberRegexp.ReplaceAllString(str, "")
  1178  	if !rxCreditCard.MatchString(sanitized) {
  1179  		return false
  1180  	}
  1181  	var sum int64
  1182  	var digit string
  1183  	var tmpNum int64
  1184  	var shouldDouble bool
  1185  	for i := len(sanitized) - 1; i >= 0; i-- {
  1186  		digit = sanitized[i:(i + 1)]
  1187  		tmpNum, _ = ToInt(digit)
  1188  		if shouldDouble {
  1189  			tmpNum *= 2
  1190  			if tmpNum >= 10 {
  1191  				sum += ((tmpNum % 10) + 1)
  1192  			} else {
  1193  				sum += tmpNum
  1194  			}
  1195  		} else {
  1196  			sum += tmpNum
  1197  		}
  1198  		shouldDouble = !shouldDouble
  1199  	}
  1200  
  1201  	return sum%10 == 0
  1202  }
  1203  
  1204  // IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
  1205  func IsIP(s string) bool {
  1206  	// ip := net.ParseIP(s)
  1207  	return s != "" && net.ParseIP(s) != nil
  1208  }
  1209  
  1210  // IsPort checks if a string represents a valid port
  1211  func IsPort(str string) bool {
  1212  	if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 {
  1213  		return true
  1214  	}
  1215  	return false
  1216  }
  1217  
  1218  // IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
  1219  func IsIPv4(s string) bool {
  1220  	if s == "" {
  1221  		return false
  1222  	}
  1223  
  1224  	ip := net.ParseIP(s)
  1225  	return ip != nil && strings.Contains(s, ".") // && ip.To4() != nil
  1226  }
  1227  
  1228  // IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
  1229  func IsIPv6(s string) bool {
  1230  	ip := net.ParseIP(s)
  1231  	return ip != nil && strings.Contains(s, ":") // && ip.To6() == nil
  1232  }
  1233  
  1234  // IsMAC check if a string is valid MAC address.
  1235  // Possible MAC formats:
  1236  // 01:23:45:67:89:ab
  1237  // 01:23:45:67:89:ab:cd:ef
  1238  // 01-23-45-67-89-ab
  1239  // 01-23-45-67-89-ab-cd-ef
  1240  // 0123.4567.89ab
  1241  // 0123.4567.89ab.cdef
  1242  func IsMAC(s string) bool {
  1243  	if s == "" {
  1244  		return false
  1245  	}
  1246  	_, err := net.ParseMAC(s)
  1247  	return err == nil
  1248  }
  1249  
  1250  // IsHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name
  1251  func IsHost(str string) bool {
  1252  	return IsIP(str) || IsDNSName(str)
  1253  }
  1254  
  1255  // IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId.
  1256  func IsMongoID(str string) bool {
  1257  	return rxHexadecimal.MatchString(str) && (len(str) == 24)
  1258  }
  1259  
  1260  // IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
  1261  func IsCIDRv4(s string) bool {
  1262  	if s == "" {
  1263  		return false
  1264  	}
  1265  	ip, _, err := net.ParseCIDR(s)
  1266  	return err == nil && ip.To4() != nil
  1267  }
  1268  
  1269  // IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
  1270  func IsCIDRv6(s string) bool {
  1271  	if s == "" {
  1272  		return false
  1273  	}
  1274  
  1275  	ip, _, err := net.ParseCIDR(s)
  1276  	return err == nil && ip.To4() == nil
  1277  }
  1278  
  1279  // IsCIDR check if the string is an valid CIDR notiation (IPV4 & IPV6)
  1280  func IsCIDR(s string) bool {
  1281  	if s == "" {
  1282  		return false
  1283  	}
  1284  
  1285  	_, _, err := net.ParseCIDR(s)
  1286  	return err == nil
  1287  }
  1288  
  1289  // IsJSON check if the string is valid JSON (note: uses json.Valid).
  1290  func IsJSON(s string) bool {
  1291  	if s == "" {
  1292  		return false
  1293  	}
  1294  
  1295  	return json.ConfigCompatibleWithStandardLibrary.Valid(Bytes(s))
  1296  }
  1297  
  1298  // HasLowerCase check if the string contains at least 1 lowercase. Empty string is valid.
  1299  func HasLowerCase(str string) bool {
  1300  	if IsNull(str) {
  1301  		return true
  1302  	}
  1303  	return rxHasLowerCase.MatchString(str)
  1304  }
  1305  
  1306  // HasUpperCase check if the string contains as least 1 uppercase. Empty string is valid.
  1307  func HasUpperCase(str string) bool {
  1308  	if IsNull(str) {
  1309  		return true
  1310  	}
  1311  	return rxHasUpperCase.MatchString(str)
  1312  }
  1313  
  1314  // StartsWith check string is starts with sub-string
  1315  func StartsWith(s, sub string) bool {
  1316  	if s == "" {
  1317  		return false
  1318  	}
  1319  
  1320  	return strings.HasPrefix(s, sub)
  1321  }
  1322  
  1323  // EndsWith check string is ends with sub-string
  1324  func EndsWith(s, sub string) bool {
  1325  	if s == "" {
  1326  		return false
  1327  	}
  1328  
  1329  	return strings.HasSuffix(s, sub)
  1330  }
  1331  
  1332  // StringContains check string is contains sub-string
  1333  func StringContains(s, sub string) bool {
  1334  	if s == "" {
  1335  		return false
  1336  	}
  1337  
  1338  	return strings.Contains(s, sub)
  1339  }
  1340  
  1341  // Regexp match value string
  1342  func Regexp(str string, pattern string) bool {
  1343  	ok, _ := regexp.MatchString(pattern, str)
  1344  	return ok
  1345  }
  1346  
  1347  /*************************************************************
  1348   * global: filesystem validators
  1349   *************************************************************/
  1350  
  1351  // PathExists reports whether the named file or directory exists.
  1352  func PathExists(path string) bool {
  1353  	if path == "" {
  1354  		return false
  1355  	}
  1356  
  1357  	if _, err := os.Stat(path); err != nil {
  1358  		if os.IsNotExist(err) {
  1359  			return false
  1360  		}
  1361  	}
  1362  	return true
  1363  }
  1364  
  1365  // IsFilePath check is a string is Win or Unix file path and returns it's type.
  1366  func IsFilePath(str string) (bool, int) {
  1367  	if rxWinPath.MatchString(str) {
  1368  		//check windows path limit see:
  1369  		//  http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath
  1370  		if len(str[3:]) > 32767 {
  1371  			return false, Win
  1372  		}
  1373  		return true, Win
  1374  	} else if rxUnixPath.MatchString(str) {
  1375  		return true, Unix
  1376  	}
  1377  	return false, Unknown
  1378  }
  1379  
  1380  func IsDirPath(path string) bool {
  1381  	if path == "" {
  1382  		return false
  1383  	}
  1384  
  1385  	if fi, err := os.Stat(path); err == nil {
  1386  		return fi.IsDir()
  1387  	}
  1388  	return false
  1389  }
  1390  
  1391  // IsWinPath string
  1392  func IsWinPath(s string) bool {
  1393  	return s != "" && rxWinPath.MatchString(s)
  1394  }
  1395  
  1396  // IsUnixPath string
  1397  func IsUnixPath(s string) bool {
  1398  	return s != "" && rxUnixPath.MatchString(s)
  1399  }
  1400  
  1401  // IsDivisibleBy check if the string is a number that's divisible by another.
  1402  // If second argument is not valid integer or zero, it's return false.
  1403  // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero).
  1404  func IsDivisibleBy(str, num string) bool {
  1405  	f, _ := ToFloat(str)
  1406  	p := int64(f)
  1407  	q, _ := ToInt(num)
  1408  	if q == 0 {
  1409  		return false
  1410  	}
  1411  	return (p == 0) || (p%q == 0)
  1412  }
  1413  
  1414  func isValidTag(s string) bool {
  1415  	if s == "" {
  1416  		return false
  1417  	}
  1418  	for _, c := range s {
  1419  		switch {
  1420  		case strings.ContainsRune("\\'\"!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
  1421  			// Backslash and quote chars are reserved, but
  1422  			// otherwise any punctuation chars are allowed
  1423  			// in a tag name.
  1424  		default:
  1425  			if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  1426  				return false
  1427  			}
  1428  		}
  1429  	}
  1430  	return true
  1431  }
  1432  
  1433  // IsSSN will validate the given string as a U.S. Social Security Number
  1434  func IsSSN(str string) bool {
  1435  	if str == "" || len(str) != 11 {
  1436  		return false
  1437  	}
  1438  	return rxSSN.MatchString(str)
  1439  }
  1440  
  1441  // IsSemver check if string is valid semantic version
  1442  func IsSemver(str string) bool {
  1443  	return rxSemver.MatchString(str)
  1444  }
  1445  
  1446  // IsType check if interface is of some type
  1447  func IsType(v interface{}, params ...string) bool {
  1448  	if len(params) == 1 {
  1449  		typ := params[0]
  1450  		return strings.Replace(reflect.TypeOf(v).String(), " ", "", -1) == strings.Replace(typ, " ", "", -1)
  1451  	}
  1452  	return false
  1453  }
  1454  
  1455  // IsTime check if string is valid according to given format
  1456  func IsTime(str string, format string) bool {
  1457  	_, err := time.Parse(format, str)
  1458  	return err == nil
  1459  }
  1460  
  1461  // IsUnixTime check if string is valid unix timestamp value
  1462  func IsUnixTime(str string) bool {
  1463  	if _, err := strconv.Atoi(str); err == nil {
  1464  		return true
  1465  	}
  1466  	return false
  1467  }
  1468  
  1469  // IsRFC3339 check if string is valid timestamp value according to RFC3339
  1470  func IsRFC3339(str string) bool {
  1471  	return IsTime(str, time.RFC3339)
  1472  }
  1473  
  1474  // IsRFC3339WithoutZone check if string is valid timestamp value according to RFC3339 which excludes the timezone.
  1475  func IsRFC3339WithoutZone(str string) bool {
  1476  	return IsTime(str, RF3339WithoutZone)
  1477  }
  1478  
  1479  // IsISO4217 check if string is valid ISO currency code
  1480  func IsISO4217(str string) bool {
  1481  	for _, currency := range ISO4217List {
  1482  		if str == currency {
  1483  			return true
  1484  		}
  1485  	}
  1486  
  1487  	return false
  1488  }
  1489  
  1490  // IsNull check if the string is null.
  1491  func IsNull(str string) bool {
  1492  	return len(str) == 0
  1493  }
  1494  
  1495  // IsNotNull check if the string is not null.
  1496  func IsNotNull(str string) bool {
  1497  	return !IsNull(str)
  1498  }
  1499  
  1500  // HasWhitespaceOnly checks the string only contains whitespace
  1501  func HasWhitespaceOnly(str string) bool {
  1502  	return len(str) > 0 && rxHasWhitespaceOnly.MatchString(str)
  1503  }
  1504  
  1505  /*************************************************************
  1506   * global: compare validators
  1507   *************************************************************/
  1508  
  1509  // Implements asserts that an object is implemented by the specified interface.
  1510  //
  1511  //    Implements((*MyInterface)(nil), new(MyObject))
  1512  func Implements(interfaceObject interface{}, object interface{}) bool {
  1513  	if object == nil {
  1514  		return false
  1515  	}
  1516  
  1517  	interfaceType := reflect.TypeOf(interfaceObject).Elem()
  1518  	return reflect.TypeOf(object).Implements(interfaceType)
  1519  }
  1520  
  1521  // AreEqual determines if two objects are considered equal.
  1522  //
  1523  // This function does no assertion of any kind.
  1524  func AreEqual(expected, actual interface{}) bool {
  1525  	if expected == nil || actual == nil {
  1526  		return expected == actual
  1527  	}
  1528  
  1529  	exp, ok := expected.([]byte)
  1530  	if !ok {
  1531  		return reflect.DeepEqual(expected, actual)
  1532  	}
  1533  
  1534  	act, ok := actual.([]byte)
  1535  	if !ok {
  1536  		return false
  1537  	}
  1538  	if exp == nil || act == nil {
  1539  		return exp == nil && act == nil
  1540  	}
  1541  	return bytes.Equal(exp, act)
  1542  }
  1543  
  1544  // AreEqualValues gets whether two objects are equal, or if their
  1545  // values are equal.
  1546  func AreEqualValues(expected, actual interface{}) bool {
  1547  	if AreEqual(expected, actual) {
  1548  		return true
  1549  	}
  1550  
  1551  	actualType := reflect.TypeOf(actual)
  1552  	if actualType == nil {
  1553  		return false
  1554  	}
  1555  	expectedValue := reflect.ValueOf(expected)
  1556  	if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
  1557  		// Attempt comparison after type conversion
  1558  		return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
  1559  	}
  1560  
  1561  	return false
  1562  }
  1563  
  1564  // IsEqual check two value is equals.
  1565  // Support:
  1566  // 	bool, int(X), uint(X), string, float(X) AND slice, array, map
  1567  func IsEqual(val, wantVal interface{}) bool {
  1568  	// check is nil
  1569  	if val == nil || wantVal == nil {
  1570  		return val == wantVal
  1571  	}
  1572  
  1573  	sv := reflect.ValueOf(val)
  1574  	wv := reflect.ValueOf(wantVal)
  1575  
  1576  	// don't compare func, struct
  1577  	if sv.Kind() == reflect.Func || sv.Kind() == reflect.Struct {
  1578  		return false
  1579  	}
  1580  	if wv.Kind() == reflect.Func || wv.Kind() == reflect.Struct {
  1581  		return false
  1582  	}
  1583  
  1584  	// compare basic type: bool, int(X), uint(X), string, float(X)
  1585  	equal, err := Eq(sv, wv)
  1586  
  1587  	// is not an basic type, eg: slice, array, map ...
  1588  	if err != nil {
  1589  		expBt, ok := val.([]byte)
  1590  		if !ok {
  1591  			return reflect.DeepEqual(val, wantVal)
  1592  		}
  1593  
  1594  		actBt, ok := wantVal.([]byte)
  1595  		if !ok {
  1596  			return false
  1597  		}
  1598  		if expBt == nil || actBt == nil {
  1599  			return expBt == nil && actBt == nil
  1600  		}
  1601  
  1602  		return bytes.Equal(expBt, actBt)
  1603  	}
  1604  
  1605  	return equal
  1606  }
  1607  
  1608  // NotEqual check
  1609  func NotEqual(val, wantVal interface{}) bool {
  1610  	return !IsEqual(val, wantVal)
  1611  }
  1612  
  1613  /*************************************************************
  1614   * global: length validators
  1615   *************************************************************/
  1616  
  1617  // CalcLength for input value
  1618  func CalcLength(val interface{}) int {
  1619  	if val == nil {
  1620  		return -1
  1621  	}
  1622  
  1623  	// string length
  1624  	if str, ok := val.(string); ok {
  1625  		return len(str)
  1626  	}
  1627  	return ValueLen(reflect.ValueOf(val))
  1628  }
  1629  
  1630  // Length equal check for string, array, slice, map
  1631  func Length(val interface{}, wantLen int) bool {
  1632  	ln := CalcLength(val)
  1633  	if ln == -1 {
  1634  		return false
  1635  	}
  1636  
  1637  	return ln == wantLen
  1638  }
  1639  
  1640  // MinLength check for string, array, slice, map
  1641  func MinLength(val interface{}, minLen int) bool {
  1642  	ln := CalcLength(val)
  1643  	if ln == -1 {
  1644  		return false
  1645  	}
  1646  
  1647  	return ln >= minLen
  1648  }
  1649  
  1650  // MaxLength check for string, array, slice, map
  1651  func MaxLength(val interface{}, maxLen int) bool {
  1652  	ln := CalcLength(val)
  1653  	if ln == -1 {
  1654  		return false
  1655  	}
  1656  
  1657  	return ln <= maxLen
  1658  }
  1659  
  1660  // ByteLength check string's length, minLen, maxLen.
  1661  func ByteLength(str string, params ...string) bool {
  1662  	if len(params) == 2 {
  1663  		min, _ := ToInt(params[0])
  1664  		max, _ := ToInt(params[1])
  1665  		return len(str) >= int(min) && len(str) <= int(max)
  1666  	}
  1667  
  1668  	return false
  1669  }
  1670  
  1671  // RuneLength check string's length, minLen, maxLen.
  1672  // Alias for StringLength
  1673  func RuneLength(str string, params ...string) bool {
  1674  	return StringLength(str, params...)
  1675  }
  1676  
  1677  // RuneLength check string's length (including multi byte strings)
  1678  func RuneLength2(val interface{}, minLen int, maxLen ...int) bool {
  1679  	str, isString := val.(string)
  1680  	if !isString {
  1681  		return false
  1682  	}
  1683  
  1684  	strLen := utf8.RuneCountInString(str)
  1685  
  1686  	// only min length check.
  1687  	if len(maxLen) == 0 {
  1688  		return strLen >= minLen
  1689  	}
  1690  
  1691  	// min and max length check
  1692  	return strLen >= minLen && strLen <= maxLen[0]
  1693  }
  1694  
  1695  // IsRsaPub check whether string is valid RSA key
  1696  // Alias for IsRsaPublicKey
  1697  func IsRsaPub(str string, params ...string) bool {
  1698  	if len(params) == 1 {
  1699  		len, _ := ToInt(params[0])
  1700  		return IsRsaPublicKey(str, int(len))
  1701  	}
  1702  
  1703  	return false
  1704  }
  1705  
  1706  // StringMatches checks if a string matches a given pattern.
  1707  func StringMatches(s string, params ...string) bool {
  1708  	if len(params) == 1 {
  1709  		pattern := params[0]
  1710  		return Matches(s, pattern)
  1711  	}
  1712  	return false
  1713  }
  1714  
  1715  // StringLength check string's length (including multi byte strings)
  1716  func StringLength(str string, params ...string) bool {
  1717  	if len(params) == 2 {
  1718  		strLength := utf8.RuneCountInString(str)
  1719  		min, _ := ToInt(params[0])
  1720  		max, _ := ToInt(params[1])
  1721  		return strLength >= int(min) && strLength <= int(max)
  1722  	}
  1723  
  1724  	return false
  1725  }
  1726  
  1727  // StringLength check string's length (including multi byte strings)
  1728  func StringLength2(val interface{}, minLen int, maxLen ...int) bool {
  1729  	return RuneLength2(val, minLen, maxLen...)
  1730  }
  1731  
  1732  // MinStringLength check string's minimum length (including multi byte strings)
  1733  func MinStringLength(str string, params ...string) bool {
  1734  
  1735  	if len(params) == 1 {
  1736  		strLength := utf8.RuneCountInString(str)
  1737  		min, _ := ToInt(params[0])
  1738  		return strLength >= int(min)
  1739  	}
  1740  
  1741  	return false
  1742  }
  1743  
  1744  // MaxStringLength check string's maximum length (including multi byte strings)
  1745  func MaxStringLength(str string, params ...string) bool {
  1746  
  1747  	if len(params) == 1 {
  1748  		strLength := utf8.RuneCountInString(str)
  1749  		max, _ := ToInt(params[0])
  1750  		return strLength <= int(max)
  1751  	}
  1752  
  1753  	return false
  1754  }
  1755  
  1756  // Range check string's length
  1757  func Range(str string, params ...string) bool {
  1758  	if len(params) == 2 {
  1759  		value, _ := ToFloat(str)
  1760  		min, _ := ToFloat(params[0])
  1761  		max, _ := ToFloat(params[1])
  1762  		return InRange(value, min, max)
  1763  	}
  1764  
  1765  	return false
  1766  }
  1767  
  1768  func IsInRaw(str string, params ...string) bool {
  1769  	if len(params) == 1 {
  1770  		rawParams := params[0]
  1771  
  1772  		parsedParams := strings.Split(rawParams, "|")
  1773  
  1774  		return IsIn(str, parsedParams...)
  1775  	}
  1776  
  1777  	return false
  1778  }
  1779  
  1780  // IsIn check if string str is a member of the set of strings params
  1781  func IsIn(str string, params ...string) bool {
  1782  	for _, param := range params {
  1783  		if str == param {
  1784  			return true
  1785  		}
  1786  	}
  1787  
  1788  	return false
  1789  }