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 }