├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── godash.go ├── godash_test.go ├── is.go ├── is_test.go ├── patterns.go ├── to.go ├── to_test.go ├── utils.go └── utils_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | temp 2 | *.sublime-project 3 | *.sublime-workspace 4 | functionlist -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | install: 4 | - go get github.com/alioygur/godash 5 | 6 | go: 7 | - 1.1 8 | - 1.2 9 | - 1.3 10 | - 1.4 11 | - 1.5 12 | - tip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Ali OYGUR 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # !!!THIS PROJECT IS NOT MAINTAINED ANYMORE!!! 2 | 3 | You can use https://github.com/alioygur/is package instead of this. 4 | 5 | # godash 6 | 7 | [![Build Status](https://travis-ci.org/alioygur/godash.svg?branch=master)](https://travis-ci.org/alioygur/godash) 8 | [![GoDoc](https://godoc.org/github.com/alioygur/godash?status.svg)](https://godoc.org/github.com/alioygur/godash) 9 | [![Go Report Card](https://goreportcard.com/badge/github.com/alioygur/godash)](https://goreportcard.com/report/github.com/alioygur/godash) 10 | 11 | A utility library in Golang inspired by lodash 12 | 13 | ## installation 14 | 15 | `go get gopkg.in/alioygur/godash.v0` 16 | 17 | ## Contribute 18 | 19 | **we are waiting your contribution** 20 | 21 | - Report problems 22 | - Add/Suggest new features/recipes 23 | - Improve/fix documentation 24 | 25 | Many thanks to our contributors: [contributors](https://github.com/alioygur/godash/graphs/contributors) 26 | 27 | 28 | ## Is* (collection of checking) 29 | 30 | An Example; 31 | 32 | ```go 33 | func IsEmail(str string) bool 34 | ``` 35 | 36 | ```go 37 | func ExampleIsEmail() { 38 | fmt.Println(IsEmail("jhon@example.com")) 39 | fmt.Println(IsEmail("invalid.com")) 40 | fmt.Println(IsEmail(`very.(),:;<>[]".VERY."very@\ "very".unusual@strange.example.com`)) 41 | // Output: 42 | // true 43 | // false 44 | // true 45 | } 46 | ``` 47 | 48 | Full list of Is* functions; 49 | 50 | ```go 51 | func IsASCII(s string) bool 52 | func IsAlpha(s string) bool 53 | func IsAlphanumeric(s string) bool 54 | func IsBase64(s string) bool 55 | func IsByteLength(str string, min, max int) bool 56 | func IsCreditCard(str string) bool 57 | func IsDNSName(str string) bool 58 | func IsDataURI(str string) bool 59 | func IsDialString(str string) bool 60 | func IsDivisibleBy(str, num string) bool 61 | func IsEmail(s string) bool 62 | func IsFilePath(str string) (bool, int) 63 | func IsFloat(str string) bool 64 | func IsFullWidth(str string) bool 65 | func IsHalfWidth(str string) bool 66 | func IsHexadecimal(str string) bool 67 | func IsHexcolor(str string) bool 68 | func IsIP(str string) bool 69 | func IsIPv4(str string) bool 70 | func IsIPv6(str string) bool 71 | func IsISBN(str string, version int) bool 72 | func IsISBN10(str string) bool 73 | func IsISBN13(str string) bool 74 | func IsISO3166Alpha2(str string) bool 75 | func IsISO3166Alpha3(str string) bool 76 | func IsInRange(value, left, right float64) bool 77 | func IsInt(str string) bool 78 | func IsJSON(str string) bool 79 | func IsLatitude(str string) bool 80 | func IsLongitude(str string) bool 81 | func IsLowerCase(str string) bool 82 | func IsMAC(str string) bool 83 | func IsMatches(str, pattern string) bool 84 | func IsMongoID(str string) bool 85 | func IsMultibyte(s string) bool 86 | func IsNatural(value float64) bool 87 | func IsNegative(value float64) bool 88 | func IsNonNegative(value float64) bool 89 | func IsNonPositive(value float64) bool 90 | func IsNull(str string) bool 91 | func IsNumeric(s string) bool 92 | func IsPort(str string) bool 93 | func IsPositive(value float64) bool 94 | func IsPrintableASCII(s string) bool 95 | func IsRGBcolor(str string) bool 96 | func IsRequestURI(rawurl string) bool 97 | func IsRequestURL(rawurl string) bool 98 | func IsSSN(str string) bool 99 | func IsSemver(str string) bool 100 | func IsStringLength(str string, params ...string) bool 101 | func IsStringMatches(s string, params ...string) bool 102 | func IsURL(str string) bool 103 | func IsUTFDigit(s string) bool 104 | func IsUTFLetter(str string) bool 105 | func IsUTFLetterNumeric(s string) bool 106 | func IsUTFNumeric(s string) bool 107 | func IsUUID(str string) bool 108 | func IsUUIDv3(str string) bool 109 | func IsUUIDv4(str string) bool 110 | func IsUUIDv5(str string) bool 111 | func IsUpperCase(str string) bool 112 | func IsVariableWidth(str string) bool 113 | func IsWhole(value float64) bool 114 | ``` 115 | 116 | ## To* (collection of converting) 117 | 118 | Examples; 119 | 120 | ```go 121 | func ExampleToBoolean() { 122 | fmt.Println(ToBoolean("True")) 123 | fmt.Println(ToBoolean("true")) 124 | fmt.Println(ToBoolean("1")) 125 | fmt.Println(ToBoolean("False")) 126 | fmt.Println(ToBoolean("false")) 127 | fmt.Println(ToBoolean("0")) 128 | // Output: 129 | // true 130 | // true 131 | // true 132 | // false 133 | // false 134 | // false 135 | } 136 | 137 | func ExampleToCamelCase() { 138 | fmt.Println(ToCamelCase("camel case")) 139 | fmt.Println(ToCamelCase(" camel case ")) 140 | fmt.Println(ToCamelCase("!!!camel case====")) 141 | fmt.Println(ToCamelCase("camel-case")) 142 | fmt.Println(ToCamelCase("camel_case")) 143 | // Output: 144 | // CamelCase 145 | // CamelCase 146 | // CamelCase 147 | // CamelCase 148 | // CamelCase 149 | } 150 | 151 | func ExampleToSnakeCase() { 152 | fmt.Println(ToSnakeCase("SnakeCase")) 153 | fmt.Println(ToSnakeCase("snake case")) 154 | fmt.Println(ToSnakeCase(" snake case ")) 155 | fmt.Println(ToSnakeCase("!!!snake case====")) 156 | fmt.Println(ToSnakeCase("snake-case")) 157 | fmt.Println(ToSnakeCase("snake_case")) 158 | // Output: 159 | // snake_case 160 | // snake_case 161 | // snake_case 162 | // snake_case 163 | // snake_case 164 | // snake_case 165 | } 166 | ``` 167 | 168 | Full list of To* functions; 169 | 170 | ```go 171 | func ToBoolean(str string) (bool, error) 172 | func ToCamelCase(s string) string 173 | func ToFloat(str string) (float64, error) 174 | func ToInt(str string) (int64, error) 175 | func ToJSON(obj interface{}) (string, error) 176 | func ToSnakeCase(str string) string 177 | func ToString(obj interface{}) string 178 | ``` 179 | 180 | for more documentation [godoc](https://godoc.org/github.com/alioygur/godash) 181 | 182 | ## Thanks & Authors 183 | 184 | I use code/got inspiration from these excellent libraries: 185 | 186 | - [asaskevich/govalidator](https://github.com/asaskevich/govalidator) [Go] Package of validators and sanitizers for strings, numerics, slices and structs 187 | - [lodash/lodash](https://github.com/lodash/lodash) A modern JavaScript utility library delivering modularity, performance, & extras. 188 | -------------------------------------------------------------------------------- /godash.go: -------------------------------------------------------------------------------- 1 | // Package godash is utility library in Golang inspired by lodash 2 | package godash 3 | 4 | // ISO3166Entry stores country codes 5 | type ISO3166Entry struct { 6 | EnglishShortName string 7 | FrenchShortName string 8 | Alpha2Code string 9 | Alpha3Code string 10 | Numeric string 11 | } 12 | 13 | //ISO3166List based on https://www.iso.org/obp/ui/#search/code/ Code Type "Officially Assigned Codes" 14 | var ISO3166List = []ISO3166Entry{ 15 | {"Afghanistan", "Afghanistan (l')", "AF", "AFG", "004"}, 16 | {"Albania", "Albanie (l')", "AL", "ALB", "008"}, 17 | {"Antarctica", "Antarctique (l')", "AQ", "ATA", "010"}, 18 | {"Algeria", "Algérie (l')", "DZ", "DZA", "012"}, 19 | {"American Samoa", "Samoa américaines (les)", "AS", "ASM", "016"}, 20 | {"Andorra", "Andorre (l')", "AD", "AND", "020"}, 21 | {"Angola", "Angola (l')", "AO", "AGO", "024"}, 22 | {"Antigua and Barbuda", "Antigua-et-Barbuda", "AG", "ATG", "028"}, 23 | {"Azerbaijan", "Azerbaïdjan (l')", "AZ", "AZE", "031"}, 24 | {"Argentina", "Argentine (l')", "AR", "ARG", "032"}, 25 | {"Australia", "Australie (l')", "AU", "AUS", "036"}, 26 | {"Austria", "Autriche (l')", "AT", "AUT", "040"}, 27 | {"Bahamas (the)", "Bahamas (les)", "BS", "BHS", "044"}, 28 | {"Bahrain", "Bahreïn", "BH", "BHR", "048"}, 29 | {"Bangladesh", "Bangladesh (le)", "BD", "BGD", "050"}, 30 | {"Armenia", "Arménie (l')", "AM", "ARM", "051"}, 31 | {"Barbados", "Barbade (la)", "BB", "BRB", "052"}, 32 | {"Belgium", "Belgique (la)", "BE", "BEL", "056"}, 33 | {"Bermuda", "Bermudes (les)", "BM", "BMU", "060"}, 34 | {"Bhutan", "Bhoutan (le)", "BT", "BTN", "064"}, 35 | {"Bolivia (Plurinational State of)", "Bolivie (État plurinational de)", "BO", "BOL", "068"}, 36 | {"Bosnia and Herzegovina", "Bosnie-Herzégovine (la)", "BA", "BIH", "070"}, 37 | {"Botswana", "Botswana (le)", "BW", "BWA", "072"}, 38 | {"Bouvet Island", "Bouvet (l'Île)", "BV", "BVT", "074"}, 39 | {"Brazil", "Brésil (le)", "BR", "BRA", "076"}, 40 | {"Belize", "Belize (le)", "BZ", "BLZ", "084"}, 41 | {"British Indian Ocean Territory (the)", "Indien (le Territoire britannique de l'océan)", "IO", "IOT", "086"}, 42 | {"Solomon Islands", "Salomon (Îles)", "SB", "SLB", "090"}, 43 | {"Virgin Islands (British)", "Vierges britanniques (les Îles)", "VG", "VGB", "092"}, 44 | {"Brunei Darussalam", "Brunéi Darussalam (le)", "BN", "BRN", "096"}, 45 | {"Bulgaria", "Bulgarie (la)", "BG", "BGR", "100"}, 46 | {"Myanmar", "Myanmar (le)", "MM", "MMR", "104"}, 47 | {"Burundi", "Burundi (le)", "BI", "BDI", "108"}, 48 | {"Belarus", "Bélarus (le)", "BY", "BLR", "112"}, 49 | {"Cambodia", "Cambodge (le)", "KH", "KHM", "116"}, 50 | {"Cameroon", "Cameroun (le)", "CM", "CMR", "120"}, 51 | {"Canada", "Canada (le)", "CA", "CAN", "124"}, 52 | {"Cabo Verde", "Cabo Verde", "CV", "CPV", "132"}, 53 | {"Cayman Islands (the)", "Caïmans (les Îles)", "KY", "CYM", "136"}, 54 | {"Central African Republic (the)", "République centrafricaine (la)", "CF", "CAF", "140"}, 55 | {"Sri Lanka", "Sri Lanka", "LK", "LKA", "144"}, 56 | {"Chad", "Tchad (le)", "TD", "TCD", "148"}, 57 | {"Chile", "Chili (le)", "CL", "CHL", "152"}, 58 | {"China", "Chine (la)", "CN", "CHN", "156"}, 59 | {"Taiwan (Province of China)", "Taïwan (Province de Chine)", "TW", "TWN", "158"}, 60 | {"Christmas Island", "Christmas (l'Île)", "CX", "CXR", "162"}, 61 | {"Cocos (Keeling) Islands (the)", "Cocos (les Îles)/ Keeling (les Îles)", "CC", "CCK", "166"}, 62 | {"Colombia", "Colombie (la)", "CO", "COL", "170"}, 63 | {"Comoros (the)", "Comores (les)", "KM", "COM", "174"}, 64 | {"Mayotte", "Mayotte", "YT", "MYT", "175"}, 65 | {"Congo (the)", "Congo (le)", "CG", "COG", "178"}, 66 | {"Congo (the Democratic Republic of the)", "Congo (la République démocratique du)", "CD", "COD", "180"}, 67 | {"Cook Islands (the)", "Cook (les Îles)", "CK", "COK", "184"}, 68 | {"Costa Rica", "Costa Rica (le)", "CR", "CRI", "188"}, 69 | {"Croatia", "Croatie (la)", "HR", "HRV", "191"}, 70 | {"Cuba", "Cuba", "CU", "CUB", "192"}, 71 | {"Cyprus", "Chypre", "CY", "CYP", "196"}, 72 | {"Czech Republic (the)", "tchèque (la République)", "CZ", "CZE", "203"}, 73 | {"Benin", "Bénin (le)", "BJ", "BEN", "204"}, 74 | {"Denmark", "Danemark (le)", "DK", "DNK", "208"}, 75 | {"Dominica", "Dominique (la)", "DM", "DMA", "212"}, 76 | {"Dominican Republic (the)", "dominicaine (la République)", "DO", "DOM", "214"}, 77 | {"Ecuador", "Équateur (l')", "EC", "ECU", "218"}, 78 | {"El Salvador", "El Salvador", "SV", "SLV", "222"}, 79 | {"Equatorial Guinea", "Guinée équatoriale (la)", "GQ", "GNQ", "226"}, 80 | {"Ethiopia", "Éthiopie (l')", "ET", "ETH", "231"}, 81 | {"Eritrea", "Érythrée (l')", "ER", "ERI", "232"}, 82 | {"Estonia", "Estonie (l')", "EE", "EST", "233"}, 83 | {"Faroe Islands (the)", "Féroé (les Îles)", "FO", "FRO", "234"}, 84 | {"Falkland Islands (the) [Malvinas]", "Falkland (les Îles)/Malouines (les Îles)", "FK", "FLK", "238"}, 85 | {"South Georgia and the South Sandwich Islands", "Géorgie du Sud-et-les Îles Sandwich du Sud (la)", "GS", "SGS", "239"}, 86 | {"Fiji", "Fidji (les)", "FJ", "FJI", "242"}, 87 | {"Finland", "Finlande (la)", "FI", "FIN", "246"}, 88 | {"Åland Islands", "Åland(les Îles)", "AX", "ALA", "248"}, 89 | {"France", "France (la)", "FR", "FRA", "250"}, 90 | {"French Guiana", "Guyane française (la )", "GF", "GUF", "254"}, 91 | {"French Polynesia", "Polynésie française (la)", "PF", "PYF", "258"}, 92 | {"French Southern Territories (the)", "Terres australes françaises (les)", "TF", "ATF", "260"}, 93 | {"Djibouti", "Djibouti", "DJ", "DJI", "262"}, 94 | {"Gabon", "Gabon (le)", "GA", "GAB", "266"}, 95 | {"Georgia", "Géorgie (la)", "GE", "GEO", "268"}, 96 | {"Gambia (the)", "Gambie (la)", "GM", "GMB", "270"}, 97 | {"Palestine, State of", "Palestine, État de", "PS", "PSE", "275"}, 98 | {"Germany", "Allemagne (l')", "DE", "DEU", "276"}, 99 | {"Ghana", "Ghana (le)", "GH", "GHA", "288"}, 100 | {"Gibraltar", "Gibraltar", "GI", "GIB", "292"}, 101 | {"Kiribati", "Kiribati", "KI", "KIR", "296"}, 102 | {"Greece", "Grèce (la)", "GR", "GRC", "300"}, 103 | {"Greenland", "Groenland (le)", "GL", "GRL", "304"}, 104 | {"Grenada", "Grenade (la)", "GD", "GRD", "308"}, 105 | {"Guadeloupe", "Guadeloupe (la)", "GP", "GLP", "312"}, 106 | {"Guam", "Guam", "GU", "GUM", "316"}, 107 | {"Guatemala", "Guatemala (le)", "GT", "GTM", "320"}, 108 | {"Guinea", "Guinée (la)", "GN", "GIN", "324"}, 109 | {"Guyana", "Guyana (le)", "GY", "GUY", "328"}, 110 | {"Haiti", "Haïti", "HT", "HTI", "332"}, 111 | {"Heard Island and McDonald Islands", "Heard-et-Îles MacDonald (l'Île)", "HM", "HMD", "334"}, 112 | {"Holy See (the)", "Saint-Siège (le)", "VA", "VAT", "336"}, 113 | {"Honduras", "Honduras (le)", "HN", "HND", "340"}, 114 | {"Hong Kong", "Hong Kong", "HK", "HKG", "344"}, 115 | {"Hungary", "Hongrie (la)", "HU", "HUN", "348"}, 116 | {"Iceland", "Islande (l')", "IS", "ISL", "352"}, 117 | {"India", "Inde (l')", "IN", "IND", "356"}, 118 | {"Indonesia", "Indonésie (l')", "ID", "IDN", "360"}, 119 | {"Iran (Islamic Republic of)", "Iran (République Islamique d')", "IR", "IRN", "364"}, 120 | {"Iraq", "Iraq (l')", "IQ", "IRQ", "368"}, 121 | {"Ireland", "Irlande (l')", "IE", "IRL", "372"}, 122 | {"Israel", "Israël", "IL", "ISR", "376"}, 123 | {"Italy", "Italie (l')", "IT", "ITA", "380"}, 124 | {"Côte d'Ivoire", "Côte d'Ivoire (la)", "CI", "CIV", "384"}, 125 | {"Jamaica", "Jamaïque (la)", "JM", "JAM", "388"}, 126 | {"Japan", "Japon (le)", "JP", "JPN", "392"}, 127 | {"Kazakhstan", "Kazakhstan (le)", "KZ", "KAZ", "398"}, 128 | {"Jordan", "Jordanie (la)", "JO", "JOR", "400"}, 129 | {"Kenya", "Kenya (le)", "KE", "KEN", "404"}, 130 | {"Korea (the Democratic People's Republic of)", "Corée (la République populaire démocratique de)", "KP", "PRK", "408"}, 131 | {"Korea (the Republic of)", "Corée (la République de)", "KR", "KOR", "410"}, 132 | {"Kuwait", "Koweït (le)", "KW", "KWT", "414"}, 133 | {"Kyrgyzstan", "Kirghizistan (le)", "KG", "KGZ", "417"}, 134 | {"Lao People's Democratic Republic (the)", "Lao, République démocratique populaire", "LA", "LAO", "418"}, 135 | {"Lebanon", "Liban (le)", "LB", "LBN", "422"}, 136 | {"Lesotho", "Lesotho (le)", "LS", "LSO", "426"}, 137 | {"Latvia", "Lettonie (la)", "LV", "LVA", "428"}, 138 | {"Liberia", "Libéria (le)", "LR", "LBR", "430"}, 139 | {"Libya", "Libye (la)", "LY", "LBY", "434"}, 140 | {"Liechtenstein", "Liechtenstein (le)", "LI", "LIE", "438"}, 141 | {"Lithuania", "Lituanie (la)", "LT", "LTU", "440"}, 142 | {"Luxembourg", "Luxembourg (le)", "LU", "LUX", "442"}, 143 | {"Macao", "Macao", "MO", "MAC", "446"}, 144 | {"Madagascar", "Madagascar", "MG", "MDG", "450"}, 145 | {"Malawi", "Malawi (le)", "MW", "MWI", "454"}, 146 | {"Malaysia", "Malaisie (la)", "MY", "MYS", "458"}, 147 | {"Maldives", "Maldives (les)", "MV", "MDV", "462"}, 148 | {"Mali", "Mali (le)", "ML", "MLI", "466"}, 149 | {"Malta", "Malte", "MT", "MLT", "470"}, 150 | {"Martinique", "Martinique (la)", "MQ", "MTQ", "474"}, 151 | {"Mauritania", "Mauritanie (la)", "MR", "MRT", "478"}, 152 | {"Mauritius", "Maurice", "MU", "MUS", "480"}, 153 | {"Mexico", "Mexique (le)", "MX", "MEX", "484"}, 154 | {"Monaco", "Monaco", "MC", "MCO", "492"}, 155 | {"Mongolia", "Mongolie (la)", "MN", "MNG", "496"}, 156 | {"Moldova (the Republic of)", "Moldova , République de", "MD", "MDA", "498"}, 157 | {"Montenegro", "Monténégro (le)", "ME", "MNE", "499"}, 158 | {"Montserrat", "Montserrat", "MS", "MSR", "500"}, 159 | {"Morocco", "Maroc (le)", "MA", "MAR", "504"}, 160 | {"Mozambique", "Mozambique (le)", "MZ", "MOZ", "508"}, 161 | {"Oman", "Oman", "OM", "OMN", "512"}, 162 | {"Namibia", "Namibie (la)", "NA", "NAM", "516"}, 163 | {"Nauru", "Nauru", "NR", "NRU", "520"}, 164 | {"Nepal", "Népal (le)", "NP", "NPL", "524"}, 165 | {"Netherlands (the)", "Pays-Bas (les)", "NL", "NLD", "528"}, 166 | {"Curaçao", "Curaçao", "CW", "CUW", "531"}, 167 | {"Aruba", "Aruba", "AW", "ABW", "533"}, 168 | {"Sint Maarten (Dutch part)", "Saint-Martin (partie néerlandaise)", "SX", "SXM", "534"}, 169 | {"Bonaire, Sint Eustatius and Saba", "Bonaire, Saint-Eustache et Saba", "BQ", "BES", "535"}, 170 | {"New Caledonia", "Nouvelle-Calédonie (la)", "NC", "NCL", "540"}, 171 | {"Vanuatu", "Vanuatu (le)", "VU", "VUT", "548"}, 172 | {"New Zealand", "Nouvelle-Zélande (la)", "NZ", "NZL", "554"}, 173 | {"Nicaragua", "Nicaragua (le)", "NI", "NIC", "558"}, 174 | {"Niger (the)", "Niger (le)", "NE", "NER", "562"}, 175 | {"Nigeria", "Nigéria (le)", "NG", "NGA", "566"}, 176 | {"Niue", "Niue", "NU", "NIU", "570"}, 177 | {"Norfolk Island", "Norfolk (l'Île)", "NF", "NFK", "574"}, 178 | {"Norway", "Norvège (la)", "NO", "NOR", "578"}, 179 | {"Northern Mariana Islands (the)", "Mariannes du Nord (les Îles)", "MP", "MNP", "580"}, 180 | {"United States Minor Outlying Islands (the)", "Îles mineures éloignées des États-Unis (les)", "UM", "UMI", "581"}, 181 | {"Micronesia (Federated States of)", "Micronésie (États fédérés de)", "FM", "FSM", "583"}, 182 | {"Marshall Islands (the)", "Marshall (Îles)", "MH", "MHL", "584"}, 183 | {"Palau", "Palaos (les)", "PW", "PLW", "585"}, 184 | {"Pakistan", "Pakistan (le)", "PK", "PAK", "586"}, 185 | {"Panama", "Panama (le)", "PA", "PAN", "591"}, 186 | {"Papua New Guinea", "Papouasie-Nouvelle-Guinée (la)", "PG", "PNG", "598"}, 187 | {"Paraguay", "Paraguay (le)", "PY", "PRY", "600"}, 188 | {"Peru", "Pérou (le)", "PE", "PER", "604"}, 189 | {"Philippines (the)", "Philippines (les)", "PH", "PHL", "608"}, 190 | {"Pitcairn", "Pitcairn", "PN", "PCN", "612"}, 191 | {"Poland", "Pologne (la)", "PL", "POL", "616"}, 192 | {"Portugal", "Portugal (le)", "PT", "PRT", "620"}, 193 | {"Guinea-Bissau", "Guinée-Bissau (la)", "GW", "GNB", "624"}, 194 | {"Timor-Leste", "Timor-Leste (le)", "TL", "TLS", "626"}, 195 | {"Puerto Rico", "Porto Rico", "PR", "PRI", "630"}, 196 | {"Qatar", "Qatar (le)", "QA", "QAT", "634"}, 197 | {"Réunion", "Réunion (La)", "RE", "REU", "638"}, 198 | {"Romania", "Roumanie (la)", "RO", "ROU", "642"}, 199 | {"Russian Federation (the)", "Russie (la Fédération de)", "RU", "RUS", "643"}, 200 | {"Rwanda", "Rwanda (le)", "RW", "RWA", "646"}, 201 | {"Saint Barthélemy", "Saint-Barthélemy", "BL", "BLM", "652"}, 202 | {"Saint Helena, Ascension and Tristan da Cunha", "Sainte-Hélène, Ascension et Tristan da Cunha", "SH", "SHN", "654"}, 203 | {"Saint Kitts and Nevis", "Saint-Kitts-et-Nevis", "KN", "KNA", "659"}, 204 | {"Anguilla", "Anguilla", "AI", "AIA", "660"}, 205 | {"Saint Lucia", "Sainte-Lucie", "LC", "LCA", "662"}, 206 | {"Saint Martin (French part)", "Saint-Martin (partie française)", "MF", "MAF", "663"}, 207 | {"Saint Pierre and Miquelon", "Saint-Pierre-et-Miquelon", "PM", "SPM", "666"}, 208 | {"Saint Vincent and the Grenadines", "Saint-Vincent-et-les Grenadines", "VC", "VCT", "670"}, 209 | {"San Marino", "Saint-Marin", "SM", "SMR", "674"}, 210 | {"Sao Tome and Principe", "Sao Tomé-et-Principe", "ST", "STP", "678"}, 211 | {"Saudi Arabia", "Arabie saoudite (l')", "SA", "SAU", "682"}, 212 | {"Senegal", "Sénégal (le)", "SN", "SEN", "686"}, 213 | {"Serbia", "Serbie (la)", "RS", "SRB", "688"}, 214 | {"Seychelles", "Seychelles (les)", "SC", "SYC", "690"}, 215 | {"Sierra Leone", "Sierra Leone (la)", "SL", "SLE", "694"}, 216 | {"Singapore", "Singapour", "SG", "SGP", "702"}, 217 | {"Slovakia", "Slovaquie (la)", "SK", "SVK", "703"}, 218 | {"Viet Nam", "Viet Nam (le)", "VN", "VNM", "704"}, 219 | {"Slovenia", "Slovénie (la)", "SI", "SVN", "705"}, 220 | {"Somalia", "Somalie (la)", "SO", "SOM", "706"}, 221 | {"South Africa", "Afrique du Sud (l')", "ZA", "ZAF", "710"}, 222 | {"Zimbabwe", "Zimbabwe (le)", "ZW", "ZWE", "716"}, 223 | {"Spain", "Espagne (l')", "ES", "ESP", "724"}, 224 | {"South Sudan", "Soudan du Sud (le)", "SS", "SSD", "728"}, 225 | {"Sudan (the)", "Soudan (le)", "SD", "SDN", "729"}, 226 | {"Western Sahara*", "Sahara occidental (le)*", "EH", "ESH", "732"}, 227 | {"Suriname", "Suriname (le)", "SR", "SUR", "740"}, 228 | {"Svalbard and Jan Mayen", "Svalbard et l'Île Jan Mayen (le)", "SJ", "SJM", "744"}, 229 | {"Swaziland", "Swaziland (le)", "SZ", "SWZ", "748"}, 230 | {"Sweden", "Suède (la)", "SE", "SWE", "752"}, 231 | {"Switzerland", "Suisse (la)", "CH", "CHE", "756"}, 232 | {"Syrian Arab Republic", "République arabe syrienne (la)", "SY", "SYR", "760"}, 233 | {"Tajikistan", "Tadjikistan (le)", "TJ", "TJK", "762"}, 234 | {"Thailand", "Thaïlande (la)", "TH", "THA", "764"}, 235 | {"Togo", "Togo (le)", "TG", "TGO", "768"}, 236 | {"Tokelau", "Tokelau (les)", "TK", "TKL", "772"}, 237 | {"Tonga", "Tonga (les)", "TO", "TON", "776"}, 238 | {"Trinidad and Tobago", "Trinité-et-Tobago (la)", "TT", "TTO", "780"}, 239 | {"United Arab Emirates (the)", "Émirats arabes unis (les)", "AE", "ARE", "784"}, 240 | {"Tunisia", "Tunisie (la)", "TN", "TUN", "788"}, 241 | {"Turkey", "Turquie (la)", "TR", "TUR", "792"}, 242 | {"Turkmenistan", "Turkménistan (le)", "TM", "TKM", "795"}, 243 | {"Turks and Caicos Islands (the)", "Turks-et-Caïcos (les Îles)", "TC", "TCA", "796"}, 244 | {"Tuvalu", "Tuvalu (les)", "TV", "TUV", "798"}, 245 | {"Uganda", "Ouganda (l')", "UG", "UGA", "800"}, 246 | {"Ukraine", "Ukraine (l')", "UA", "UKR", "804"}, 247 | {"Macedonia (the former Yugoslav Republic of)", "Macédoine (l'ex‑République yougoslave de)", "MK", "MKD", "807"}, 248 | {"Egypt", "Égypte (l')", "EG", "EGY", "818"}, 249 | {"United Kingdom of Great Britain and Northern Ireland (the)", "Royaume-Uni de Grande-Bretagne et d'Irlande du Nord (le)", "GB", "GBR", "826"}, 250 | {"Guernsey", "Guernesey", "GG", "GGY", "831"}, 251 | {"Jersey", "Jersey", "JE", "JEY", "832"}, 252 | {"Isle of Man", "Île de Man", "IM", "IMN", "833"}, 253 | {"Tanzania, United Republic of", "Tanzanie, République-Unie de", "TZ", "TZA", "834"}, 254 | {"United States of America (the)", "États-Unis d'Amérique (les)", "US", "USA", "840"}, 255 | {"Virgin Islands (U.S.)", "Vierges des États-Unis (les Îles)", "VI", "VIR", "850"}, 256 | {"Burkina Faso", "Burkina Faso (le)", "BF", "BFA", "854"}, 257 | {"Uruguay", "Uruguay (l')", "UY", "URY", "858"}, 258 | {"Uzbekistan", "Ouzbékistan (l')", "UZ", "UZB", "860"}, 259 | {"Venezuela (Bolivarian Republic of)", "Venezuela (République bolivarienne du)", "VE", "VEN", "862"}, 260 | {"Wallis and Futuna", "Wallis-et-Futuna", "WF", "WLF", "876"}, 261 | {"Samoa", "Samoa (le)", "WS", "WSM", "882"}, 262 | {"Yemen", "Yémen (le)", "YE", "YEM", "887"}, 263 | {"Zambia", "Zambie (la)", "ZM", "ZMB", "894"}, 264 | } 265 | -------------------------------------------------------------------------------- /godash_test.go: -------------------------------------------------------------------------------- 1 | package godash 2 | -------------------------------------------------------------------------------- /is.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/json" 6 | "math" 7 | "net" 8 | "net/url" 9 | "regexp" 10 | "strconv" 11 | "strings" 12 | "unicode" 13 | "unicode/utf8" 14 | ) 15 | 16 | // IsInRange returns true if value lies between left and right border 17 | func IsInRange(value, left, right float64) bool { 18 | if left > right { 19 | left, right = right, left 20 | } 21 | return value >= left && value <= right 22 | } 23 | 24 | // IsEmail is a constraint to do a simple validation for email addresses, it only check if the string contains "@" 25 | // and that it is not in the first or last character of the string 26 | // https://en.wikipedia.org/wiki/Email_address#Valid_email_addresses 27 | func IsEmail(s string) bool { 28 | if !strings.Contains(s, "@") || string(s[0]) == "@" || string(s[len(s)-1]) == "@" { 29 | return false 30 | } 31 | return true 32 | } 33 | 34 | // IsURL check if the string is an URL. 35 | func IsURL(str string) bool { 36 | if str == "" || len(str) >= 2083 || len(str) <= 3 || strings.HasPrefix(str, ".") { 37 | return false 38 | } 39 | u, err := url.Parse(str) 40 | if err != nil { 41 | return false 42 | } 43 | if strings.HasPrefix(u.Host, ".") { 44 | return false 45 | } 46 | if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { 47 | return false 48 | } 49 | return rxURL.MatchString(str) 50 | 51 | } 52 | 53 | // IsRequestURL check if the string rawurl, assuming 54 | // it was recieved in an HTTP request, is a valid 55 | // URL confirm to RFC 3986 56 | func IsRequestURL(rawurl string) bool { 57 | url, err := url.ParseRequestURI(rawurl) 58 | if err != nil { 59 | return false //Couldn't even parse the rawurl 60 | } 61 | if len(url.Scheme) == 0 { 62 | return false //No Scheme found 63 | } 64 | return true 65 | } 66 | 67 | // IsRequestURI check if the string rawurl, assuming 68 | // it was recieved in an HTTP request, is an 69 | // absolute URI or an absolute path. 70 | func IsRequestURI(rawurl string) bool { 71 | _, err := url.ParseRequestURI(rawurl) 72 | return err == nil 73 | } 74 | 75 | // IsAlpha check if the string contains only letters (a-zA-Z). Empty string is valid. 76 | func IsAlpha(s string) bool { 77 | for _, v := range s { 78 | if ('Z' < v || v < 'A') && ('z' < v || v < 'a') { 79 | return false 80 | } 81 | } 82 | return true 83 | } 84 | 85 | //IsUTFLetter check if the string contains only unicode letter characters. 86 | //Similar to IsAlpha but for all languages. Empty string is valid. 87 | func IsUTFLetter(str string) bool { 88 | for _, v := range str { 89 | if !unicode.IsLetter(v) { 90 | return false 91 | } 92 | } 93 | return true 94 | 95 | } 96 | 97 | // IsAlphanumeric check if the string contains only letters and numbers. Empty string is valid. 98 | func IsAlphanumeric(s string) bool { 99 | for _, v := range s { 100 | if ('Z' < v || v < 'A') && ('z' < v || v < 'a') && ('9' < v || v < '0') { 101 | return false 102 | } 103 | } 104 | return true 105 | } 106 | 107 | // IsUTFLetterNumeric check if the string contains only unicode letters and numbers. Empty string is valid. 108 | func IsUTFLetterNumeric(s string) bool { 109 | for _, v := range s { 110 | if !unicode.IsLetter(v) && !unicode.IsNumber(v) { //letters && numbers are ok 111 | return false 112 | } 113 | } 114 | return true 115 | } 116 | 117 | // IsNumeric check if the string contains only numbers. Empty string is valid. 118 | func IsNumeric(s string) bool { 119 | for _, v := range s { 120 | if '9' < v || v < '0' { 121 | return false 122 | } 123 | } 124 | return true 125 | } 126 | 127 | // IsUTFNumeric check if the string contains only unicode numbers of any kind. 128 | // Numbers can be 0-9 but also Fractions ¾,Roman Ⅸ and Hangzhou 〩. Empty string is valid. 129 | func IsUTFNumeric(s string) bool { 130 | for _, v := range s { 131 | if unicode.IsNumber(v) == false { 132 | return false 133 | } 134 | } 135 | return true 136 | } 137 | 138 | // IsNegative returns true if value < 0 139 | func IsNegative(value float64) bool { 140 | return value < 0 141 | } 142 | 143 | // IsPositive returns true if value > 0 144 | func IsPositive(value float64) bool { 145 | return value > 0 146 | } 147 | 148 | // IsNonNegative returns true if value >= 0 149 | func IsNonNegative(value float64) bool { 150 | return value >= 0 151 | } 152 | 153 | // IsNonPositive returns true if value <= 0 154 | func IsNonPositive(value float64) bool { 155 | return value <= 0 156 | } 157 | 158 | // IsWhole returns true if value is whole number 159 | func IsWhole(value float64) bool { 160 | return math.Abs(math.Remainder(value, 1)) == 0 161 | } 162 | 163 | // IsNatural returns true if value is natural number (positive and whole) 164 | func IsNatural(value float64) bool { 165 | return IsWhole(value) && IsPositive(value) 166 | } 167 | 168 | // IsUTFDigit check if the string contains only unicode radix-10 decimal digits. Empty string is valid. 169 | func IsUTFDigit(s string) bool { 170 | for _, v := range s { 171 | if !unicode.IsDigit(v) { 172 | return false 173 | } 174 | } 175 | return true 176 | } 177 | 178 | // IsHexadecimal check if the string is a hexadecimal number. 179 | func IsHexadecimal(str string) bool { 180 | return rxHexadecimal.MatchString(str) 181 | } 182 | 183 | // IsHexcolor check if the string is a hexadecimal color. 184 | func IsHexcolor(str string) bool { 185 | return rxHexcolor.MatchString(str) 186 | } 187 | 188 | // IsRGBcolor check if the string is a valid RGB color in form rgb(RRR, GGG, BBB). 189 | func IsRGBcolor(str string) bool { 190 | return rxRGBcolor.MatchString(str) 191 | } 192 | 193 | // IsLowerCase check if the string is lowercase. Empty string is valid. 194 | func IsLowerCase(str string) bool { 195 | if IsNull(str) { 196 | return true 197 | } 198 | return str == strings.ToLower(str) 199 | } 200 | 201 | // IsUpperCase check if the string is uppercase. Empty string is valid. 202 | func IsUpperCase(str string) bool { 203 | if IsNull(str) { 204 | return true 205 | } 206 | return str == strings.ToUpper(str) 207 | } 208 | 209 | // IsInt check if the string is an integer. Empty string is valid. 210 | func IsInt(str string) bool { 211 | if IsNull(str) { 212 | return true 213 | } 214 | return rxInt.MatchString(str) 215 | } 216 | 217 | // IsFloat check if the string is a float. 218 | func IsFloat(str string) bool { 219 | return str != "" && rxFloat.MatchString(str) 220 | } 221 | 222 | // IsDivisibleBy check if the string is a number that's divisible by another. 223 | // If second argument is not valid integer or zero, it's return false. 224 | // Otherwise, if first argument is not valid integer or zero, it's return true (Invalid string converts to zero). 225 | func IsDivisibleBy(str, num string) bool { 226 | f, _ := ToFloat(str) 227 | p := int64(f) 228 | q, _ := ToInt(num) 229 | if q == 0 { 230 | return false 231 | } 232 | return (p == 0) || (p%q == 0) 233 | } 234 | 235 | // IsNull check if the string is null. 236 | func IsNull(str string) bool { 237 | return len(str) == 0 238 | } 239 | 240 | // IsByteLength check if the string's length (in bytes) falls in a range. 241 | func IsByteLength(str string, min, max int) bool { 242 | return len(str) >= min && len(str) <= max 243 | } 244 | 245 | // IsUUIDv3 check if the string is a UUID version 3. 246 | func IsUUIDv3(str string) bool { 247 | return rxUUID3.MatchString(str) 248 | } 249 | 250 | // IsUUIDv4 check if the string is a UUID version 4. 251 | func IsUUIDv4(str string) bool { 252 | return rxUUID4.MatchString(str) 253 | } 254 | 255 | // IsUUIDv5 check if the string is a UUID version 5. 256 | func IsUUIDv5(str string) bool { 257 | return rxUUID5.MatchString(str) 258 | } 259 | 260 | // IsUUID check if the string is a UUID (version 3, 4 or 5). 261 | func IsUUID(str string) bool { 262 | return rxUUID.MatchString(str) 263 | } 264 | 265 | // IsCreditCard check if the string is a credit card. 266 | func IsCreditCard(str string) bool { 267 | r, _ := regexp.Compile("[^0-9]+") 268 | sanitized := r.ReplaceAll([]byte(str), []byte("")) 269 | if !rxCreditCard.MatchString(string(sanitized)) { 270 | return false 271 | } 272 | var sum int64 273 | var digit string 274 | var tmpNum int64 275 | var shouldDouble bool 276 | for i := len(sanitized) - 1; i >= 0; i-- { 277 | digit = string(sanitized[i:(i + 1)]) 278 | tmpNum, _ = ToInt(digit) 279 | if shouldDouble { 280 | tmpNum *= 2 281 | if tmpNum >= 10 { 282 | sum += ((tmpNum % 10) + 1) 283 | } else { 284 | sum += tmpNum 285 | } 286 | } else { 287 | sum += tmpNum 288 | } 289 | shouldDouble = !shouldDouble 290 | } 291 | 292 | if sum%10 == 0 { 293 | return true 294 | } 295 | return false 296 | } 297 | 298 | // IsISBN10 check if the string is an ISBN version 10. 299 | func IsISBN10(str string) bool { 300 | return IsISBN(str, 10) 301 | } 302 | 303 | // IsISBN13 check if the string is an ISBN version 13. 304 | func IsISBN13(str string) bool { 305 | return IsISBN(str, 13) 306 | } 307 | 308 | // IsISBN check if the string is an ISBN (version 10 or 13). 309 | // If version value is not equal to 10 or 13, it will be check both variants. 310 | func IsISBN(str string, version int) bool { 311 | r, _ := regexp.Compile("[\\s-]+") 312 | sanitized := r.ReplaceAll([]byte(str), []byte("")) 313 | var checksum int32 314 | var i int32 315 | if version == 10 { 316 | if !rxISBN10.MatchString(string(sanitized)) { 317 | return false 318 | } 319 | for i = 0; i < 9; i++ { 320 | checksum += (i + 1) * int32(sanitized[i]-'0') 321 | } 322 | if sanitized[9] == 'X' { 323 | checksum += 10 * 10 324 | } else { 325 | checksum += 10 * int32(sanitized[9]-'0') 326 | } 327 | if checksum%11 == 0 { 328 | return true 329 | } 330 | return false 331 | } else if version == 13 { 332 | if !rxISBN13.MatchString(string(sanitized)) { 333 | return false 334 | } 335 | factor := []int32{1, 3} 336 | for i = 0; i < 12; i++ { 337 | checksum += factor[i%2] * int32(sanitized[i]-'0') 338 | } 339 | if (int32(sanitized[12]-'0'))-((10-(checksum%10))%10) == 0 { 340 | return true 341 | } 342 | return false 343 | } 344 | return IsISBN(str, 10) || IsISBN(str, 13) 345 | } 346 | 347 | // IsJSON check if the string is valid JSON (note: uses json.Unmarshal). 348 | func IsJSON(str string) bool { 349 | var js json.RawMessage 350 | return json.Unmarshal([]byte(str), &js) == nil 351 | } 352 | 353 | // IsMultibyte check if the string contains one or more multibyte chars. Empty string is valid. 354 | func IsMultibyte(s string) bool { 355 | for _, v := range s { 356 | if v >= utf8.RuneSelf { 357 | return true 358 | } 359 | } 360 | 361 | return IsNull(s) 362 | } 363 | 364 | // IsASCII check if the string contains ASCII chars only. Empty string is valid. 365 | func IsASCII(s string) bool { 366 | for _, v := range s { 367 | if v >= utf8.RuneSelf { 368 | return false 369 | } 370 | } 371 | return true 372 | } 373 | 374 | // IsPrintableASCII check if the string contains printable ASCII chars only. Empty string is valid. 375 | func IsPrintableASCII(s string) bool { 376 | for _, v := range s { 377 | if v < ' ' || v > '~' { 378 | return false 379 | } 380 | } 381 | return true 382 | } 383 | 384 | // IsFullWidth check if the string contains any full-width chars. Empty string is valid. 385 | func IsFullWidth(str string) bool { 386 | if IsNull(str) { 387 | return true 388 | } 389 | return rxFullWidth.MatchString(str) 390 | } 391 | 392 | // IsHalfWidth check if the string contains any half-width chars. Empty string is valid. 393 | func IsHalfWidth(str string) bool { 394 | if IsNull(str) { 395 | return true 396 | } 397 | return rxHalfWidth.MatchString(str) 398 | } 399 | 400 | // IsVariableWidth check if the string contains a mixture of full and half-width chars. Empty string is valid. 401 | func IsVariableWidth(str string) bool { 402 | if IsNull(str) { 403 | return true 404 | } 405 | return rxHalfWidth.MatchString(str) && rxFullWidth.MatchString(str) 406 | } 407 | 408 | // IsBase64 check if a string is base64 encoded. 409 | func IsBase64(s string) bool { 410 | if IsNull(s) { 411 | return false 412 | } 413 | _, err := base64.StdEncoding.DecodeString(s) 414 | 415 | return err == nil 416 | } 417 | 418 | // IsFilePath check is a string is Win or Unix file path and returns it's type. 419 | func IsFilePath(str string) (bool, int) { 420 | if rxWinPath.MatchString(str) { 421 | //check windows path limit see: 422 | // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath 423 | if len(str[3:]) > 32767 { 424 | return false, Win 425 | } 426 | return true, Win 427 | } else if rxUnixPath.MatchString(str) { 428 | return true, Unix 429 | } 430 | return false, Unknown 431 | } 432 | 433 | // IsDataURI checks if a string is base64 encoded data URI such as an image 434 | func IsDataURI(str string) bool { 435 | dataURI := strings.Split(str, ",") 436 | if !rxDataURI.MatchString(dataURI[0]) { 437 | return false 438 | } 439 | return IsBase64(dataURI[1]) 440 | } 441 | 442 | // IsISO3166Alpha2 checks if a string is valid two-letter country code 443 | func IsISO3166Alpha2(str string) bool { 444 | for _, entry := range ISO3166List { 445 | if str == entry.Alpha2Code { 446 | return true 447 | } 448 | } 449 | return false 450 | } 451 | 452 | // IsISO3166Alpha3 checks if a string is valid three-letter country code 453 | func IsISO3166Alpha3(str string) bool { 454 | for _, entry := range ISO3166List { 455 | if str == entry.Alpha3Code { 456 | return true 457 | } 458 | } 459 | return false 460 | } 461 | 462 | // IsDNSName will validate the given string as a DNS name 463 | func IsDNSName(str string) bool { 464 | if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 { 465 | // constraints already violated 466 | return false 467 | } 468 | return rxDNSName.MatchString(str) 469 | } 470 | 471 | // IsDialString validates the given string for usage with the various Dial() functions 472 | func IsDialString(str string) bool { 473 | 474 | if h, p, err := net.SplitHostPort(str); err == nil && h != "" && p != "" && (IsDNSName(h) || IsIP(h)) && IsPort(p) { 475 | return true 476 | } 477 | 478 | return false 479 | } 480 | 481 | // IsIP checks if a string is either IP version 4 or 6. 482 | func IsIP(str string) bool { 483 | return net.ParseIP(str) != nil 484 | } 485 | 486 | // IsPort checks if a string represents a valid port 487 | func IsPort(str string) bool { 488 | if i, err := strconv.Atoi(str); err == nil && i > 0 && i < 65536 { 489 | return true 490 | } 491 | return false 492 | } 493 | 494 | // IsIPv4 check if the string is an IP version 4. 495 | func IsIPv4(str string) bool { 496 | ip := net.ParseIP(str) 497 | return ip != nil && strings.Contains(str, ".") 498 | } 499 | 500 | // IsIPv6 check if the string is an IP version 6. 501 | func IsIPv6(str string) bool { 502 | ip := net.ParseIP(str) 503 | return ip != nil && strings.Contains(str, ":") 504 | } 505 | 506 | // IsMAC check if a string is valid MAC address. 507 | // Possible MAC formats: 508 | // 01:23:45:67:89:ab 509 | // 01:23:45:67:89:ab:cd:ef 510 | // 01-23-45-67-89-ab 511 | // 01-23-45-67-89-ab-cd-ef 512 | // 0123.4567.89ab 513 | // 0123.4567.89ab.cdef 514 | func IsMAC(str string) bool { 515 | _, err := net.ParseMAC(str) 516 | return err == nil 517 | } 518 | 519 | // IsMongoID check if the string is a valid hex-encoded representation of a MongoDB ObjectId. 520 | func IsMongoID(str string) bool { 521 | return rxHexadecimal.MatchString(str) && (len(str) == 24) 522 | } 523 | 524 | // IsLatitude check if a string is valid latitude. 525 | func IsLatitude(str string) bool { 526 | return rxLatitude.MatchString(str) 527 | } 528 | 529 | // IsLongitude check if a string is valid longitude. 530 | func IsLongitude(str string) bool { 531 | return rxLongitude.MatchString(str) 532 | } 533 | 534 | // IsSSN will validate the given string as a U.S. Social Security Number 535 | func IsSSN(str string) bool { 536 | if str == "" || len(str) != 11 { 537 | return false 538 | } 539 | return rxSSN.MatchString(str) 540 | } 541 | 542 | // IsSemver check if string is valid semantic version 543 | func IsSemver(str string) bool { 544 | return rxSemver.MatchString(str) 545 | } 546 | 547 | // IsMatches check if string matches the pattern (pattern is regular expression) 548 | // In case of error return false 549 | func IsMatches(str, pattern string) bool { 550 | match, _ := regexp.MatchString(pattern, str) 551 | return match 552 | } 553 | 554 | // IsStringMatches checks if a string matches a given pattern. 555 | func IsStringMatches(s string, params ...string) bool { 556 | if len(params) == 1 { 557 | pattern := params[0] 558 | return IsMatches(s, pattern) 559 | } 560 | return false 561 | } 562 | 563 | // IsStringLength check string's length (including multi byte strings) 564 | func IsStringLength(str string, params ...string) bool { 565 | 566 | if len(params) == 2 { 567 | strLength := utf8.RuneCountInString(str) 568 | min, _ := ToInt(params[0]) 569 | max, _ := ToInt(params[1]) 570 | return strLength >= int(min) && strLength <= int(max) 571 | } 572 | 573 | return false 574 | } 575 | -------------------------------------------------------------------------------- /is_test.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestIsAlpha(t *testing.T) { 10 | t.Parallel() 11 | 12 | var tests = []struct { 13 | param string 14 | expected bool 15 | }{ 16 | {"\n", false}, 17 | {"\r", false}, 18 | {"Ⅸ", false}, 19 | {"", true}, 20 | {" fooo ", false}, 21 | {"abc!!!", false}, 22 | {"abc1", false}, 23 | {"abc〩", false}, 24 | {"abc", true}, 25 | {"소주", false}, 26 | {"ABC", true}, 27 | {"FoObAr", true}, 28 | {"소aBC", false}, 29 | {"소", false}, 30 | {"달기&Co.", false}, 31 | {"〩Hours", false}, 32 | {"\ufff0", false}, 33 | {"\u0070", true}, //UTF-8(ASCII): p 34 | {"\u0026", false}, //UTF-8(ASCII): & 35 | {"\u0030", false}, //UTF-8(ASCII): 0 36 | {"123", false}, 37 | {"0123", false}, 38 | {"-00123", false}, 39 | {"0", false}, 40 | {"-0", false}, 41 | {"123.123", false}, 42 | {" ", false}, 43 | {".", false}, 44 | {"-1¾", false}, 45 | {"1¾", false}, 46 | {"〥〩", false}, 47 | {"모자", false}, 48 | {"ix", true}, 49 | {"۳۵۶۰", false}, 50 | {"1--", false}, 51 | {"1-1", false}, 52 | {"-", false}, 53 | {"--", false}, 54 | {"1++", false}, 55 | {"1+1", false}, 56 | {"+", false}, 57 | {"++", false}, 58 | {"+1", false}, 59 | } 60 | for _, test := range tests { 61 | actual := IsAlpha(test.param) 62 | if actual != test.expected { 63 | t.Errorf("Expected IsAlpha(%q) to be %v, got %v", test.param, test.expected, actual) 64 | } 65 | } 66 | } 67 | 68 | func TestIsUTFLetter(t *testing.T) { 69 | t.Parallel() 70 | 71 | var tests = []struct { 72 | param string 73 | expected bool 74 | }{ 75 | {"\n", false}, 76 | {"\r", false}, 77 | {"Ⅸ", false}, 78 | {"", true}, 79 | {" fooo ", false}, 80 | {"abc!!!", false}, 81 | {"abc1", false}, 82 | {"abc〩", false}, 83 | {"", true}, 84 | {"abc", true}, 85 | {"소주", true}, 86 | {"ABC", true}, 87 | {"FoObAr", true}, 88 | {"소aBC", true}, 89 | {"소", true}, 90 | {"달기&Co.", false}, 91 | {"〩Hours", false}, 92 | {"\ufff0", false}, 93 | {"\u0070", true}, //UTF-8(ASCII): p 94 | {"\u0026", false}, //UTF-8(ASCII): & 95 | {"\u0030", false}, //UTF-8(ASCII): 0 96 | {"123", false}, 97 | {"0123", false}, 98 | {"-00123", false}, 99 | {"0", false}, 100 | {"-0", false}, 101 | {"123.123", false}, 102 | {" ", false}, 103 | {".", false}, 104 | {"-1¾", false}, 105 | {"1¾", false}, 106 | {"〥〩", false}, 107 | {"모자", true}, 108 | {"ix", true}, 109 | {"۳۵۶۰", false}, 110 | {"1--", false}, 111 | {"1-1", false}, 112 | {"-", false}, 113 | {"--", false}, 114 | {"1++", false}, 115 | {"1+1", false}, 116 | {"+", false}, 117 | {"++", false}, 118 | {"+1", false}, 119 | } 120 | for _, test := range tests { 121 | actual := IsUTFLetter(test.param) 122 | if actual != test.expected { 123 | t.Errorf("Expected IsUTFLetter(%q) to be %v, got %v", test.param, test.expected, actual) 124 | } 125 | } 126 | } 127 | 128 | func TestIsAlphanumeric(t *testing.T) { 129 | t.Parallel() 130 | 131 | var tests = []struct { 132 | param string 133 | expected bool 134 | }{ 135 | {"\n", false}, 136 | {"\r", false}, 137 | {"Ⅸ", false}, 138 | {"", true}, 139 | {" fooo ", false}, 140 | {"abc!!!", false}, 141 | {"abc123", true}, 142 | {"ABC111", true}, 143 | {"abc1", true}, 144 | {"abc〩", false}, 145 | {"abc", true}, 146 | {"소주", false}, 147 | {"ABC", true}, 148 | {"FoObAr", true}, 149 | {"소aBC", false}, 150 | {"소", false}, 151 | {"달기&Co.", false}, 152 | {"〩Hours", false}, 153 | {"\ufff0", false}, 154 | {"\u0070", true}, //UTF-8(ASCII): p 155 | {"\u0026", false}, //UTF-8(ASCII): & 156 | {"\u0030", true}, //UTF-8(ASCII): 0 157 | {"123", true}, 158 | {"0123", true}, 159 | {"-00123", false}, 160 | {"0", true}, 161 | {"-0", false}, 162 | {"123.123", false}, 163 | {" ", false}, 164 | {".", false}, 165 | {"-1¾", false}, 166 | {"1¾", false}, 167 | {"〥〩", false}, 168 | {"모자", false}, 169 | {"ix", true}, 170 | {"۳۵۶۰", false}, 171 | {"1--", false}, 172 | {"1-1", false}, 173 | {"-", false}, 174 | {"--", false}, 175 | {"1++", false}, 176 | {"1+1", false}, 177 | {"+", false}, 178 | {"++", false}, 179 | {"+1", false}, 180 | } 181 | for _, test := range tests { 182 | actual := IsAlphanumeric(test.param) 183 | if actual != test.expected { 184 | t.Errorf("Expected IsAlphanumeric(%q) to be %v, got %v", test.param, test.expected, actual) 185 | } 186 | } 187 | } 188 | 189 | func TestIsUTFLetterNumeric(t *testing.T) { 190 | t.Parallel() 191 | 192 | var tests = []struct { 193 | param string 194 | expected bool 195 | }{ 196 | {"\n", false}, 197 | {"\r", false}, 198 | {"Ⅸ", true}, 199 | {"", true}, 200 | {" fooo ", false}, 201 | {"abc!!!", false}, 202 | {"abc1", true}, 203 | {"abc〩", true}, 204 | {"abc", true}, 205 | {"소주", true}, 206 | {"ABC", true}, 207 | {"FoObAr", true}, 208 | {"소aBC", true}, 209 | {"소", true}, 210 | {"달기&Co.", false}, 211 | {"〩Hours", true}, 212 | {"\ufff0", false}, 213 | {"\u0070", true}, //UTF-8(ASCII): p 214 | {"\u0026", false}, //UTF-8(ASCII): & 215 | {"\u0030", true}, //UTF-8(ASCII): 0 216 | {"123", true}, 217 | {"0123", true}, 218 | {"-00123", false}, 219 | {"0", true}, 220 | {"-0", false}, 221 | {"123.123", false}, 222 | {" ", false}, 223 | {".", false}, 224 | {"-1¾", false}, 225 | {"1¾", true}, 226 | {"〥〩", true}, 227 | {"모자", true}, 228 | {"ix", true}, 229 | {"۳۵۶۰", true}, 230 | {"1--", false}, 231 | {"1-1", false}, 232 | {"-", false}, 233 | {"--", false}, 234 | {"1++", false}, 235 | {"1+1", false}, 236 | {"+", false}, 237 | {"++", false}, 238 | {"+1", false}, 239 | } 240 | for _, test := range tests { 241 | actual := IsUTFLetterNumeric(test.param) 242 | if actual != test.expected { 243 | t.Errorf("Expected IsUTFLetterNumeric(%q) to be %v, got %v", test.param, test.expected, actual) 244 | } 245 | } 246 | } 247 | 248 | func TestIsNumeric(t *testing.T) { 249 | t.Parallel() 250 | 251 | var tests = []struct { 252 | param string 253 | expected bool 254 | }{ 255 | {"\n", false}, 256 | {"\r", false}, 257 | {"Ⅸ", false}, 258 | {"", true}, 259 | {" fooo ", false}, 260 | {"abc!!!", false}, 261 | {"abc1", false}, 262 | {"abc〩", false}, 263 | {"abc", false}, 264 | {"소주", false}, 265 | {"ABC", false}, 266 | {"FoObAr", false}, 267 | {"소aBC", false}, 268 | {"소", false}, 269 | {"달기&Co.", false}, 270 | {"〩Hours", false}, 271 | {"\ufff0", false}, 272 | {"\u0070", false}, //UTF-8(ASCII): p 273 | {"\u0026", false}, //UTF-8(ASCII): & 274 | {"\u0030", true}, //UTF-8(ASCII): 0 275 | {"123", true}, 276 | {"0123", true}, 277 | {"-00123", false}, 278 | {"+00123", false}, 279 | {"0", true}, 280 | {"-0", false}, 281 | {"123.123", false}, 282 | {" ", false}, 283 | {".", false}, 284 | {"12𐅪3", false}, 285 | {"-1¾", false}, 286 | {"1¾", false}, 287 | {"〥〩", false}, 288 | {"모자", false}, 289 | {"ix", false}, 290 | {"۳۵۶۰", false}, 291 | {"1--", false}, 292 | {"1-1", false}, 293 | {"-", false}, 294 | {"--", false}, 295 | {"1++", false}, 296 | {"1+1", false}, 297 | {"+", false}, 298 | {"++", false}, 299 | {"+1", false}, 300 | } 301 | for _, test := range tests { 302 | actual := IsNumeric(test.param) 303 | if actual != test.expected { 304 | t.Errorf("Expected IsNumeric(%q) to be %v, got %v", test.param, test.expected, actual) 305 | } 306 | } 307 | } 308 | 309 | func TestIsUTFNumeric(t *testing.T) { 310 | t.Parallel() 311 | 312 | var tests = []struct { 313 | param string 314 | expected bool 315 | }{ 316 | {"\n", false}, 317 | {"\r", false}, 318 | {"Ⅸ", true}, 319 | {"", true}, 320 | {" fooo ", false}, 321 | {"abc!!!", false}, 322 | {"abc1", false}, 323 | {"abc〩", false}, 324 | {"abc", false}, 325 | {"소주", false}, 326 | {"ABC", false}, 327 | {"FoObAr", false}, 328 | {"소aBC", false}, 329 | {"소", false}, 330 | {"달기&Co.", false}, 331 | {"〩Hours", false}, 332 | {"\ufff0", false}, 333 | {"\u0070", false}, //UTF-8(ASCII): p 334 | {"\u0026", false}, //UTF-8(ASCII): & 335 | {"\u0030", true}, //UTF-8(ASCII): 0 336 | {"123", true}, 337 | {"0123", true}, 338 | {"-00123", false}, 339 | {"0", true}, 340 | {"-0", false}, 341 | {"--0", false}, 342 | {"-0-", false}, 343 | {"123.123", false}, 344 | {" ", false}, 345 | {".", false}, 346 | {"12𐅪3", true}, 347 | {"-1¾", false}, 348 | {"1¾", true}, 349 | {"〥〩", true}, 350 | {"모자", false}, 351 | {"ix", false}, 352 | {"۳۵۶۰", true}, 353 | {"1++", false}, 354 | {"1+1", false}, 355 | {"+", false}, 356 | {"++", false}, 357 | {"+1", false}, 358 | } 359 | for _, test := range tests { 360 | actual := IsUTFNumeric(test.param) 361 | if actual != test.expected { 362 | t.Errorf("Expected IsUTFNumeric(%q) to be %v, got %v", test.param, test.expected, actual) 363 | } 364 | } 365 | } 366 | 367 | func TestIsUTFDigit(t *testing.T) { 368 | t.Parallel() 369 | 370 | var tests = []struct { 371 | param string 372 | expected bool 373 | }{ 374 | {"\n", false}, 375 | {"\r", false}, 376 | {"Ⅸ", false}, 377 | {"", true}, 378 | {" fooo ", false}, 379 | {"abc!!!", false}, 380 | {"abc1", false}, 381 | {"abc〩", false}, 382 | {"abc", false}, 383 | {"소주", false}, 384 | {"ABC", false}, 385 | {"FoObAr", false}, 386 | {"소aBC", false}, 387 | {"소", false}, 388 | {"달기&Co.", false}, 389 | {"〩Hours", false}, 390 | {"\ufff0", false}, 391 | {"\u0070", false}, //UTF-8(ASCII): p 392 | {"\u0026", false}, //UTF-8(ASCII): & 393 | {"\u0030", true}, //UTF-8(ASCII): 0 394 | {"123", true}, 395 | {"0123", true}, 396 | {"-00123", false}, 397 | {"0", true}, 398 | {"-0", false}, 399 | {"--0", false}, 400 | {"-0-", false}, 401 | {"123.123", false}, 402 | {" ", false}, 403 | {".", false}, 404 | {"12𐅪3", false}, 405 | {"1483920", true}, 406 | {"", true}, 407 | {"۳۵۶۰", true}, 408 | {"-29", false}, 409 | {"-1¾", false}, 410 | {"1¾", false}, 411 | {"〥〩", false}, 412 | {"모자", false}, 413 | {"ix", false}, 414 | {"۳۵۶۰", true}, 415 | {"1++", false}, 416 | {"1+1", false}, 417 | {"+", false}, 418 | {"++", false}, 419 | {"+1", false}, 420 | } 421 | for _, test := range tests { 422 | actual := IsUTFDigit(test.param) 423 | if actual != test.expected { 424 | t.Errorf("Expected IsUTFDigit(%q) to be %v, got %v", test.param, test.expected, actual) 425 | } 426 | } 427 | } 428 | 429 | func TestIsLowerCase(t *testing.T) { 430 | t.Parallel() 431 | 432 | var tests = []struct { 433 | param string 434 | expected bool 435 | }{ 436 | {"", true}, 437 | {"abc123", true}, 438 | {"abc", true}, 439 | {"a b c", true}, 440 | {"abcß", true}, 441 | {"abcẞ", false}, 442 | {"ABCẞ", false}, 443 | {"tr竪s 端ber", true}, 444 | {"fooBar", false}, 445 | {"123ABC", false}, 446 | {"ABC123", false}, 447 | {"ABC", false}, 448 | {"S T R", false}, 449 | {"fooBar", false}, 450 | {"abacaba123", true}, 451 | } 452 | for _, test := range tests { 453 | actual := IsLowerCase(test.param) 454 | if actual != test.expected { 455 | t.Errorf("Expected IsLowerCase(%q) to be %v, got %v", test.param, test.expected, actual) 456 | } 457 | } 458 | } 459 | 460 | func TestIsUpperCase(t *testing.T) { 461 | t.Parallel() 462 | 463 | var tests = []struct { 464 | param string 465 | expected bool 466 | }{ 467 | {"", true}, 468 | {"abc123", false}, 469 | {"abc", false}, 470 | {"a b c", false}, 471 | {"abcß", false}, 472 | {"abcẞ", false}, 473 | {"ABCẞ", true}, 474 | {"tr竪s 端ber", false}, 475 | {"fooBar", false}, 476 | {"123ABC", true}, 477 | {"ABC123", true}, 478 | {"ABC", true}, 479 | {"S T R", true}, 480 | {"fooBar", false}, 481 | {"abacaba123", false}, 482 | } 483 | for _, test := range tests { 484 | actual := IsUpperCase(test.param) 485 | if actual != test.expected { 486 | t.Errorf("Expected IsUpperCase(%q) to be %v, got %v", test.param, test.expected, actual) 487 | } 488 | } 489 | } 490 | 491 | func TestIsInt(t *testing.T) { 492 | t.Parallel() 493 | 494 | var tests = []struct { 495 | param string 496 | expected bool 497 | }{ 498 | {"-2147483648", true}, //Signed 32 Bit Min Int 499 | {"2147483647", true}, //Signed 32 Bit Max Int 500 | {"-2147483649", true}, //Signed 32 Bit Min Int - 1 501 | {"2147483648", true}, //Signed 32 Bit Max Int + 1 502 | {"4294967295", true}, //Unsigned 32 Bit Max Int 503 | {"4294967296", true}, //Unsigned 32 Bit Max Int + 1 504 | {"-9223372036854775808", true}, //Signed 64 Bit Min Int 505 | {"9223372036854775807", true}, //Signed 64 Bit Max Int 506 | {"-9223372036854775809", true}, //Signed 64 Bit Min Int - 1 507 | {"9223372036854775808", true}, //Signed 64 Bit Max Int + 1 508 | {"18446744073709551615", true}, //Unsigned 64 Bit Max Int 509 | {"18446744073709551616", true}, //Unsigned 64 Bit Max Int + 1 510 | {"", true}, 511 | {"123", true}, 512 | {"0", true}, 513 | {"-0", true}, 514 | {"+0", true}, 515 | {"01", false}, 516 | {"123.123", false}, 517 | {" ", false}, 518 | {"000", false}, 519 | } 520 | for _, test := range tests { 521 | actual := IsInt(test.param) 522 | if actual != test.expected { 523 | t.Errorf("Expected IsInt(%q) to be %v, got %v", test.param, test.expected, actual) 524 | } 525 | } 526 | } 527 | 528 | func TestIsEmail(t *testing.T) { 529 | t.Parallel() 530 | 531 | var tests = []struct { 532 | param string 533 | expected bool 534 | }{ 535 | {``, false}, 536 | {`foo@bar.com`, true}, 537 | {`x@x.x`, true}, 538 | {`foo@bar.com.au`, true}, 539 | {`foo+bar@bar.com`, true}, 540 | {`foo@bar.coffee`, true}, 541 | {`foo@bar.中文网`, true}, 542 | {`invalidemail@`, false}, 543 | {`invalid.com`, false}, 544 | {`@invalid.com`, false}, 545 | {`test|123@m端ller.com`, true}, 546 | {`hans@m端ller.com`, true}, 547 | {`hans.m端ller@test.com`, true}, 548 | {`NathAn.daVIeS@DomaIn.cOM`, true}, 549 | {`NATHAN.DAVIES@DOMAIN.CO.UK`, true}, 550 | {`very.(),:;<>[]".VERY."very@\ "very".unusual@strange.example.com`, true}, 551 | } 552 | for _, test := range tests { 553 | actual := IsEmail(test.param) 554 | if actual != test.expected { 555 | t.Errorf("Expected IsEmail(%q) to be %v, got %v", test.param, test.expected, actual) 556 | } 557 | } 558 | } 559 | 560 | func ExampleIsEmail() { 561 | fmt.Println(IsEmail("jhon@example.com")) 562 | fmt.Println(IsEmail("invalid.com")) 563 | fmt.Println(IsEmail(`very.(),:;<>[]".VERY."very@\ "very".unusual@strange.example.com`)) 564 | // Output: 565 | // true 566 | // false 567 | // true 568 | } 569 | 570 | func TestIsURL(t *testing.T) { 571 | t.Parallel() 572 | 573 | var tests = []struct { 574 | param string 575 | expected bool 576 | }{ 577 | {"", false}, 578 | {"http://foo.bar#com", true}, 579 | {"http://foobar.com", true}, 580 | {"https://foobar.com", true}, 581 | {"foobar.com", true}, 582 | {"http://foobar.coffee/", true}, 583 | {"http://foobar.中文网/", true}, 584 | {"http://foobar.org/", true}, 585 | {"http://foobar.org:8080/", true}, 586 | {"ftp://foobar.ru/", true}, 587 | {"ftp.foo.bar", true}, 588 | {"http://user:pass@www.foobar.com/", true}, 589 | {"http://user:pass@www.foobar.com/path/file", true}, 590 | {"http://127.0.0.1/", true}, 591 | {"http://duckduckgo.com/?q=%2F", true}, 592 | {"http://localhost:3000/", true}, 593 | {"http://foobar.com/?foo=bar#baz=qux", true}, 594 | {"http://foobar.com?foo=bar", true}, 595 | {"http://www.xn--froschgrn-x9a.net/", true}, 596 | {"http://foobar.com/a-", true}, 597 | {"http://foobar.پاکستان/", true}, 598 | {"http://foobar.c_o_m", false}, 599 | {"", false}, 600 | {"xyz://foobar.com", false}, 601 | {"invalid.", false}, 602 | {".com", false}, 603 | {"rtmp://foobar.com", false}, 604 | {"http://www.foo_bar.com/", false}, 605 | {"http://localhost:3000/", true}, 606 | {"http://foobar.com#baz=qux", true}, 607 | {"http://foobar.com/t$-_.+!*\\'(),", true}, 608 | {"http://www.foobar.com/~foobar", true}, 609 | {"http://www.-foobar.com/", false}, 610 | {"http://www.foo---bar.com/", false}, 611 | {"mailto:someone@example.com", true}, 612 | {"irc://irc.server.org/channel", false}, 613 | {"irc://#channel@network", true}, 614 | {"/abs/test/dir", false}, 615 | {"./rel/test/dir", false}, 616 | {"http://foo^bar.org", false}, 617 | {"http://foo&*bar.org", false}, 618 | {"http://foo&bar.org", false}, 619 | {"http://foo bar.org", false}, 620 | {"http://foo.bar.org", true}, 621 | {"http://www.foo.bar.org", true}, 622 | {"http://www.foo.co.uk", true}, 623 | {"foo", false}, 624 | {"http://.foo.com", false}, 625 | {"http://,foo.com", false}, 626 | {",foo.com", false}, 627 | // according to issues #62 #66 628 | {"https://pbs.twimg.com/profile_images/560826135676588032/j8fWrmYY_normal.jpeg", true}, 629 | {"http://me.example.com", true}, 630 | {"http://www.me.example.com", true}, 631 | {"https://farm6.static.flickr.com", true}, 632 | {"https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5", true}, 633 | {"google", false}, 634 | // According to #87 635 | {"http://hyphenated-host-name.example.co.in", true}, 636 | {"http://cant-end-with-hyphen-.example.com", false}, 637 | {"http://-cant-start-with-hyphen.example.com", false}, 638 | {"http://www.domain-can-have-dashes.com", true}, 639 | } 640 | for _, test := range tests { 641 | actual := IsURL(test.param) 642 | if actual != test.expected { 643 | t.Errorf("Expected IsURL(%q) to be %v, got %v", test.param, test.expected, actual) 644 | } 645 | } 646 | } 647 | 648 | func TestIsRequestURL(t *testing.T) { 649 | t.Parallel() 650 | 651 | var tests = []struct { 652 | param string 653 | expected bool 654 | }{ 655 | {"", false}, 656 | // {"http://foo.bar#com", false}, goversion < 1.6: true, goversion > 1.5: false 657 | {"http://foobar.com", true}, 658 | {"https://foobar.com", true}, 659 | {"foobar.com", false}, 660 | {"http://foobar.coffee/", true}, 661 | {"http://foobar.中文网/", true}, 662 | {"http://foobar.org/", true}, 663 | {"http://foobar.org:8080/", true}, 664 | {"ftp://foobar.ru/", true}, 665 | {"http://user:pass@www.foobar.com/", true}, 666 | {"http://127.0.0.1/", true}, 667 | {"http://duckduckgo.com/?q=%2F", true}, 668 | {"http://localhost:3000/", true}, 669 | {"http://foobar.com/?foo=bar#baz=qux", true}, 670 | {"http://foobar.com?foo=bar", true}, 671 | {"http://www.xn--froschgrn-x9a.net/", true}, 672 | {"", false}, 673 | {"xyz://foobar.com", true}, 674 | {"invalid.", false}, 675 | {".com", false}, 676 | {"rtmp://foobar.com", true}, 677 | {"http://www.foo_bar.com/", true}, 678 | {"http://localhost:3000/", true}, 679 | // {"http://foobar.com#baz=qux", false}, goversion < 1.6: true, goversion > 1.5: false 680 | {"http://foobar.com/t$-_.+!*\\'(),", true}, 681 | {"http://www.foobar.com/~foobar", true}, 682 | {"http://www.-foobar.com/", true}, 683 | {"http://www.foo---bar.com/", true}, 684 | {"mailto:someone@example.com", true}, 685 | {"irc://irc.server.org/channel", true}, 686 | {"irc://#channel@network", true}, 687 | {"/abs/test/dir", false}, 688 | {"./rel/test/dir", false}, 689 | } 690 | for _, test := range tests { 691 | actual := IsRequestURL(test.param) 692 | if actual != test.expected { 693 | t.Errorf("Expected IsRequestURL(%q) to be %v, got %v", test.param, test.expected, actual) 694 | } 695 | } 696 | } 697 | 698 | func TestIsRequestURI(t *testing.T) { 699 | t.Parallel() 700 | 701 | var tests = []struct { 702 | param string 703 | expected bool 704 | }{ 705 | {"", false}, 706 | // {"http://foo.bar#com", false}, goversion < 1.6: true, goversion > 1.5: false 707 | {"http://foobar.com", true}, 708 | {"https://foobar.com", true}, 709 | {"foobar.com", false}, 710 | {"http://foobar.coffee/", true}, 711 | {"http://foobar.中文网/", true}, 712 | {"http://foobar.org/", true}, 713 | {"http://foobar.org:8080/", true}, 714 | {"ftp://foobar.ru/", true}, 715 | {"http://user:pass@www.foobar.com/", true}, 716 | {"http://127.0.0.1/", true}, 717 | {"http://duckduckgo.com/?q=%2F", true}, 718 | {"http://localhost:3000/", true}, 719 | {"http://foobar.com/?foo=bar#baz=qux", true}, 720 | {"http://foobar.com?foo=bar", true}, 721 | {"http://www.xn--froschgrn-x9a.net/", true}, 722 | {"xyz://foobar.com", true}, 723 | {"invalid.", false}, 724 | {".com", false}, 725 | {"rtmp://foobar.com", true}, 726 | {"http://www.foo_bar.com/", true}, 727 | {"http://localhost:3000/", true}, 728 | // {"http://foobar.com#baz=qux", false}, goversion < 1.6: true, goversion > 1.5: false 729 | {"http://foobar.com/t$-_.+!*\\'(),", true}, 730 | {"http://www.foobar.com/~foobar", true}, 731 | {"http://www.-foobar.com/", true}, 732 | {"http://www.foo---bar.com/", true}, 733 | {"mailto:someone@example.com", true}, 734 | {"irc://irc.server.org/channel", true}, 735 | {"irc://#channel@network", true}, 736 | {"/abs/test/dir", true}, 737 | {"./rel/test/dir", false}, 738 | } 739 | for _, test := range tests { 740 | actual := IsRequestURI(test.param) 741 | if actual != test.expected { 742 | t.Errorf("Expected IsRequestURI(%q) to be %v, got %v", test.param, test.expected, actual) 743 | } 744 | } 745 | } 746 | 747 | func TestIsFloat(t *testing.T) { 748 | t.Parallel() 749 | 750 | var tests = []struct { 751 | param string 752 | expected bool 753 | }{ 754 | {"", false}, 755 | {" ", false}, 756 | {"-.123", false}, 757 | {"abacaba", false}, 758 | {"1f", false}, 759 | {"-1f", false}, 760 | {"+1f", false}, 761 | {"123", true}, 762 | {"123.", true}, 763 | {"123.123", true}, 764 | {"-123.123", true}, 765 | {"+123.123", true}, 766 | {"0.123", true}, 767 | {"-0.123", true}, 768 | {"+0.123", true}, 769 | {".0", true}, 770 | {"01.123", true}, 771 | {"-0.22250738585072011e-307", true}, 772 | {"+0.22250738585072011e-307", true}, 773 | } 774 | for _, test := range tests { 775 | actual := IsFloat(test.param) 776 | if actual != test.expected { 777 | t.Errorf("Expected IsFloat(%q) to be %v, got %v", test.param, test.expected, actual) 778 | } 779 | } 780 | } 781 | 782 | func TestIsHexadecimal(t *testing.T) { 783 | t.Parallel() 784 | 785 | var tests = []struct { 786 | param string 787 | expected bool 788 | }{ 789 | {"abcdefg", false}, 790 | {"", false}, 791 | {"..", false}, 792 | {"deadBEEF", true}, 793 | {"ff0044", true}, 794 | } 795 | for _, test := range tests { 796 | actual := IsHexadecimal(test.param) 797 | if actual != test.expected { 798 | t.Errorf("Expected IsHexadecimal(%q) to be %v, got %v", test.param, test.expected, actual) 799 | } 800 | } 801 | } 802 | 803 | func TestIsHexcolor(t *testing.T) { 804 | t.Parallel() 805 | 806 | var tests = []struct { 807 | param string 808 | expected bool 809 | }{ 810 | {"", false}, 811 | {"#ff", false}, 812 | {"fff0", false}, 813 | {"#ff12FG", false}, 814 | {"CCccCC", true}, 815 | {"fff", true}, 816 | {"#f00", true}, 817 | } 818 | for _, test := range tests { 819 | actual := IsHexcolor(test.param) 820 | if actual != test.expected { 821 | t.Errorf("Expected IsHexcolor(%q) to be %v, got %v", test.param, test.expected, actual) 822 | } 823 | } 824 | } 825 | 826 | func TestIsRGBcolor(t *testing.T) { 827 | t.Parallel() 828 | 829 | var tests = []struct { 830 | param string 831 | expected bool 832 | }{ 833 | {"", false}, 834 | {"rgb(0,31,255)", true}, 835 | {"rgb(1,349,275)", false}, 836 | {"rgb(01,31,255)", false}, 837 | {"rgb(0.6,31,255)", false}, 838 | {"rgba(0,31,255)", false}, 839 | {"rgb(0, 31, 255)", true}, 840 | } 841 | for _, test := range tests { 842 | actual := IsRGBcolor(test.param) 843 | if actual != test.expected { 844 | t.Errorf("Expected IsRGBcolor(%q) to be %v, got %v", test.param, test.expected, actual) 845 | } 846 | } 847 | } 848 | 849 | func TestIsNull(t *testing.T) { 850 | t.Parallel() 851 | 852 | var tests = []struct { 853 | param string 854 | expected bool 855 | }{ 856 | {"abacaba", false}, 857 | {"", true}, 858 | } 859 | for _, test := range tests { 860 | actual := IsNull(test.param) 861 | if actual != test.expected { 862 | t.Errorf("Expected IsNull(%q) to be %v, got %v", test.param, test.expected, actual) 863 | } 864 | } 865 | } 866 | 867 | func TestIsDivisibleBy(t *testing.T) { 868 | t.Parallel() 869 | 870 | var tests = []struct { 871 | param1 string 872 | param2 string 873 | expected bool 874 | }{ 875 | {"4", "2", true}, 876 | {"100", "10", true}, 877 | {"", "1", true}, 878 | {"123", "foo", false}, 879 | {"123", "0", false}, 880 | } 881 | for _, test := range tests { 882 | actual := IsDivisibleBy(test.param1, test.param2) 883 | if actual != test.expected { 884 | t.Errorf("Expected IsDivisibleBy(%q, %q) to be %v, got %v", test.param1, test.param2, test.expected, actual) 885 | } 886 | } 887 | } 888 | 889 | // This small example illustrate how to work with IsDivisibleBy function. 890 | func ExampleIsDivisibleBy() { 891 | println("1024 is divisible by 64: ", IsDivisibleBy("1024", "64")) 892 | } 893 | 894 | func TestIsByteLength(t *testing.T) { 895 | t.Parallel() 896 | 897 | var tests = []struct { 898 | param1 string 899 | param2 int 900 | param3 int 901 | expected bool 902 | }{ 903 | {"abacaba", 100, -1, false}, 904 | {"abacaba", 1, 3, false}, 905 | {"abacaba", 1, 7, true}, 906 | {"abacaba", 0, 8, true}, 907 | {"\ufff0", 1, 1, false}, 908 | } 909 | for _, test := range tests { 910 | actual := IsByteLength(test.param1, test.param2, test.param3) 911 | if actual != test.expected { 912 | t.Errorf("Expected IsByteLength(%q, %q, %q) to be %v, got %v", test.param1, test.param2, test.param3, test.expected, actual) 913 | } 914 | } 915 | } 916 | 917 | func TestIsJSON(t *testing.T) { 918 | t.Parallel() 919 | 920 | var tests = []struct { 921 | param string 922 | expected bool 923 | }{ 924 | {"", false}, 925 | {"145", true}, 926 | {"asdf", false}, 927 | {"123:f00", false}, 928 | {"{\"Name\":\"Alice\",\"Body\":\"Hello\",\"Time\":1294706395881547000}", true}, 929 | {"{}", true}, 930 | {"{\"Key\":{\"Key\":{\"Key\":123}}}", true}, 931 | {"[]", true}, 932 | {"null", true}, 933 | } 934 | for _, test := range tests { 935 | actual := IsJSON(test.param) 936 | if actual != test.expected { 937 | t.Errorf("Expected IsJSON(%q) to be %v, got %v", test.param, test.expected, actual) 938 | } 939 | } 940 | } 941 | 942 | func TestIsMultibyte(t *testing.T) { 943 | t.Parallel() 944 | 945 | var tests = []struct { 946 | param string 947 | expected bool 948 | }{ 949 | {"abc", false}, 950 | {"123", false}, 951 | {"<>@;.-=", false}, 952 | {"ひらがな・カタカナ、.漢字", true}, 953 | {"あいうえお foobar", true}, 954 | {"test@example.com", true}, 955 | {"test@example.com", true}, 956 | {"1234abcDExyz", true}, 957 | {"カタカナ", true}, 958 | {"~", false}, 959 | } 960 | for _, test := range tests { 961 | actual := IsMultibyte(test.param) 962 | if actual != test.expected { 963 | t.Errorf("Expected IsMultibyte(%q) to be %v, got %v", test.param, test.expected, actual) 964 | } 965 | } 966 | } 967 | 968 | func TestIsASCII(t *testing.T) { 969 | t.Parallel() 970 | 971 | var tests = []struct { 972 | param string 973 | expected bool 974 | }{ 975 | {"", true}, 976 | {"foobar", false}, 977 | {"xyz098", false}, 978 | {"123456", false}, 979 | {"カタカナ", false}, 980 | {"foobar", true}, 981 | {"0987654321", true}, 982 | {"test@example.com", true}, 983 | {"1234abcDEF", true}, 984 | {"", true}, 985 | } 986 | for _, test := range tests { 987 | actual := IsASCII(test.param) 988 | if actual != test.expected { 989 | t.Errorf("Expected IsASCII(%q) to be %v, got %v", test.param, test.expected, actual) 990 | } 991 | } 992 | } 993 | 994 | func TestIsPrintableASCII(t *testing.T) { 995 | t.Parallel() 996 | 997 | var tests = []struct { 998 | param string 999 | expected bool 1000 | }{ 1001 | {"", true}, 1002 | {"foobar", false}, 1003 | {"xyz098", false}, 1004 | {"123456", false}, 1005 | {"カタカナ", false}, 1006 | {"foobar", true}, 1007 | {"0987654321", true}, 1008 | {"test@example.com", true}, 1009 | {"1234abcDEF", true}, 1010 | {"newline\n", false}, 1011 | {"\x19test\x7F", false}, 1012 | } 1013 | for _, test := range tests { 1014 | actual := IsPrintableASCII(test.param) 1015 | if actual != test.expected { 1016 | t.Errorf("Expected IsPrintableASCII(%q) to be %v, got %v", test.param, test.expected, actual) 1017 | } 1018 | } 1019 | } 1020 | 1021 | func TestIsFullWidth(t *testing.T) { 1022 | t.Parallel() 1023 | 1024 | var tests = []struct { 1025 | param string 1026 | expected bool 1027 | }{ 1028 | {"", true}, 1029 | {"abc", false}, 1030 | {"abc123", false}, 1031 | {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, 1032 | {"ひらがな・カタカナ、.漢字", true}, 1033 | {"3ー0 a@com", true}, 1034 | {"Fカタカナ゙ᆲ", true}, 1035 | {"Good=Parts", true}, 1036 | {"", true}, 1037 | } 1038 | for _, test := range tests { 1039 | actual := IsFullWidth(test.param) 1040 | if actual != test.expected { 1041 | t.Errorf("Expected IsFullWidth(%q) to be %v, got %v", test.param, test.expected, actual) 1042 | } 1043 | } 1044 | } 1045 | 1046 | func TestIsHalfWidth(t *testing.T) { 1047 | t.Parallel() 1048 | 1049 | var tests = []struct { 1050 | param string 1051 | expected bool 1052 | }{ 1053 | {"", true}, 1054 | {"あいうえお", false}, 1055 | {"0011", false}, 1056 | {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", true}, 1057 | {"l-btn_02--active", true}, 1058 | {"abc123い", true}, 1059 | {"カタカナ゙ᆲ←", true}, 1060 | {"", true}, 1061 | } 1062 | for _, test := range tests { 1063 | actual := IsHalfWidth(test.param) 1064 | if actual != test.expected { 1065 | t.Errorf("Expected IsHalfWidth(%q) to be %v, got %v", test.param, test.expected, actual) 1066 | } 1067 | } 1068 | } 1069 | 1070 | func TestIsVariableWidth(t *testing.T) { 1071 | t.Parallel() 1072 | 1073 | var tests = []struct { 1074 | param string 1075 | expected bool 1076 | }{ 1077 | {"", true}, 1078 | {"ひらがなカタカナ漢字ABCDE", true}, 1079 | {"3ー0123", true}, 1080 | {"Fカタカナ゙ᆲ", true}, 1081 | {"", true}, 1082 | {"Good=Parts", true}, 1083 | {"abc", false}, 1084 | {"abc123", false}, 1085 | {"!\"#$%&()<>/+=-_? ~^|.,@`{}[]", false}, 1086 | {"ひらがな・カタカナ、.漢字", false}, 1087 | {"123456", false}, 1088 | {"カタカナ゙ᆲ", false}, 1089 | } 1090 | for _, test := range tests { 1091 | actual := IsVariableWidth(test.param) 1092 | if actual != test.expected { 1093 | t.Errorf("Expected IsVariableWidth(%q) to be %v, got %v", test.param, test.expected, actual) 1094 | } 1095 | } 1096 | } 1097 | 1098 | func TestIsUUID(t *testing.T) { 1099 | t.Parallel() 1100 | 1101 | // Tests without version 1102 | var tests = []struct { 1103 | param string 1104 | expected bool 1105 | }{ 1106 | {"", false}, 1107 | {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, 1108 | {"a987fbc9-4bed-3078-cf07-9141ba07c9f3xxx", false}, 1109 | {"a987fbc94bed3078cf079141ba07c9f3", false}, 1110 | {"934859", false}, 1111 | {"987fbc9-4bed-3078-cf07a-9141ba07c9f3", false}, 1112 | {"aaaaaaaa-1111-1111-aaag-111111111111", false}, 1113 | {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, 1114 | } 1115 | for _, test := range tests { 1116 | actual := IsUUID(test.param) 1117 | if actual != test.expected { 1118 | t.Errorf("Expected IsUUID(%q) to be %v, got %v", test.param, test.expected, actual) 1119 | } 1120 | } 1121 | 1122 | // UUID ver. 3 1123 | tests = []struct { 1124 | param string 1125 | expected bool 1126 | }{ 1127 | {"", false}, 1128 | {"412452646", false}, 1129 | {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, 1130 | {"a987fbc9-4bed-4078-8f07-9141ba07c9f3", false}, 1131 | {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", true}, 1132 | } 1133 | for _, test := range tests { 1134 | actual := IsUUIDv3(test.param) 1135 | if actual != test.expected { 1136 | t.Errorf("Expected IsUUIDv3(%q) to be %v, got %v", test.param, test.expected, actual) 1137 | } 1138 | } 1139 | 1140 | // UUID ver. 4 1141 | tests = []struct { 1142 | param string 1143 | expected bool 1144 | }{ 1145 | {"", false}, 1146 | {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, 1147 | {"a987fbc9-4bed-5078-af07-9141ba07c9f3", false}, 1148 | {"934859", false}, 1149 | {"57b73598-8764-4ad0-a76a-679bb6640eb1", true}, 1150 | {"625e63f3-58f5-40b7-83a1-a72ad31acffb", true}, 1151 | } 1152 | for _, test := range tests { 1153 | actual := IsUUIDv4(test.param) 1154 | if actual != test.expected { 1155 | t.Errorf("Expected IsUUIDv4(%q) to be %v, got %v", test.param, test.expected, actual) 1156 | } 1157 | } 1158 | 1159 | // UUID ver. 5 1160 | tests = []struct { 1161 | param string 1162 | expected bool 1163 | }{ 1164 | 1165 | {"", false}, 1166 | {"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, 1167 | {"9c858901-8a57-4791-81fe-4c455b099bc9", false}, 1168 | {"a987fbc9-4bed-3078-cf07-9141ba07c9f3", false}, 1169 | {"987fbc97-4bed-5078-af07-9141ba07c9f3", true}, 1170 | {"987fbc97-4bed-5078-9f07-9141ba07c9f3", true}, 1171 | } 1172 | for _, test := range tests { 1173 | actual := IsUUIDv5(test.param) 1174 | if actual != test.expected { 1175 | t.Errorf("Expected IsUUIDv5(%q) to be %v, got %v", test.param, test.expected, actual) 1176 | } 1177 | } 1178 | } 1179 | 1180 | func TestIsCreditCard(t *testing.T) { 1181 | t.Parallel() 1182 | 1183 | var tests = []struct { 1184 | param string 1185 | expected bool 1186 | }{ 1187 | {"", false}, 1188 | {"foo", false}, 1189 | {"5398228707871528", false}, 1190 | {"375556917985515", true}, 1191 | {"36050234196908", true}, 1192 | {"4716461583322103", true}, 1193 | {"4716-2210-5188-5662", true}, 1194 | {"4929 7226 5379 7141", true}, 1195 | {"5398228707871527", true}, 1196 | } 1197 | for _, test := range tests { 1198 | actual := IsCreditCard(test.param) 1199 | if actual != test.expected { 1200 | t.Errorf("Expected IsCreditCard(%q) to be %v, got %v", test.param, test.expected, actual) 1201 | } 1202 | } 1203 | } 1204 | 1205 | func TestIsISBN(t *testing.T) { 1206 | t.Parallel() 1207 | 1208 | // Without version 1209 | var tests = []struct { 1210 | param string 1211 | expected bool 1212 | }{ 1213 | {"", false}, 1214 | {"foo", false}, 1215 | {"3836221195", true}, 1216 | {"1-61729-085-8", true}, 1217 | {"3 423 21412 0", true}, 1218 | {"3 401 01319 X", true}, 1219 | {"9784873113685", true}, 1220 | {"978-4-87311-368-5", true}, 1221 | {"978 3401013190", true}, 1222 | {"978-3-8362-2119-1", true}, 1223 | } 1224 | for _, test := range tests { 1225 | actual := IsISBN(test.param, -1) 1226 | if actual != test.expected { 1227 | t.Errorf("Expected IsISBN(%q, -1) to be %v, got %v", test.param, test.expected, actual) 1228 | } 1229 | } 1230 | 1231 | // ISBN 10 1232 | tests = []struct { 1233 | param string 1234 | expected bool 1235 | }{ 1236 | {"", false}, 1237 | {"foo", false}, 1238 | {"3423214121", false}, 1239 | {"978-3836221191", false}, 1240 | {"3-423-21412-1", false}, 1241 | {"3 423 21412 1", false}, 1242 | {"3836221195", true}, 1243 | {"1-61729-085-8", true}, 1244 | {"3 423 21412 0", true}, 1245 | {"3 401 01319 X", true}, 1246 | } 1247 | for _, test := range tests { 1248 | actual := IsISBN10(test.param) 1249 | if actual != test.expected { 1250 | t.Errorf("Expected IsISBN10(%q) to be %v, got %v", test.param, test.expected, actual) 1251 | } 1252 | } 1253 | 1254 | // ISBN 13 1255 | tests = []struct { 1256 | param string 1257 | expected bool 1258 | }{ 1259 | {"", false}, 1260 | {"foo", false}, 1261 | {"3-8362-2119-5", false}, 1262 | {"01234567890ab", false}, 1263 | {"978 3 8362 2119 0", false}, 1264 | {"9784873113685", true}, 1265 | {"978-4-87311-368-5", true}, 1266 | {"978 3401013190", true}, 1267 | {"978-3-8362-2119-1", true}, 1268 | } 1269 | for _, test := range tests { 1270 | actual := IsISBN13(test.param) 1271 | if actual != test.expected { 1272 | t.Errorf("Expected IsISBN13(%q) to be %v, got %v", test.param, test.expected, actual) 1273 | } 1274 | } 1275 | } 1276 | 1277 | func TestIsDataURI(t *testing.T) { 1278 | t.Parallel() 1279 | 1280 | var tests = []struct { 1281 | param string 1282 | expected bool 1283 | }{ 1284 | {"data:image/png;base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, 1285 | {"data:text/plain;base64,Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, 1286 | {"image/gif;base64,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, 1287 | {"data:image/gif;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + 1288 | "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + 1289 | "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + 1290 | "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + 1291 | "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + 1292 | "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, 1293 | {"data:image/png;base64,12345", false}, 1294 | {"", false}, 1295 | {"data:text,:;base85,U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", false}, 1296 | } 1297 | for _, test := range tests { 1298 | actual := IsDataURI(test.param) 1299 | if actual != test.expected { 1300 | t.Errorf("Expected IsDataURI(%q) to be %v, got %v", test.param, test.expected, actual) 1301 | } 1302 | } 1303 | } 1304 | 1305 | func TestIsBase64(t *testing.T) { 1306 | t.Parallel() 1307 | 1308 | var tests = []struct { 1309 | param string 1310 | expected bool 1311 | }{ 1312 | {"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=", true}, 1313 | {"Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==", true}, 1314 | {"U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==", true}, 1315 | {"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw" + 1316 | "UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye" + 1317 | "rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619" + 1318 | "FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx" + 1319 | "QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ" + 1320 | "Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ" + "HQIDAQAB", true}, 1321 | {"12345", false}, 1322 | {"", false}, 1323 | {"Vml2YW11cyBmZXJtZtesting123", false}, 1324 | } 1325 | for _, test := range tests { 1326 | actual := IsBase64(test.param) 1327 | if actual != test.expected { 1328 | t.Errorf("Expected IsBase64(%q) to be %v, got %v", test.param, test.expected, actual) 1329 | } 1330 | } 1331 | } 1332 | 1333 | func TestIsISO3166Alpha2(t *testing.T) { 1334 | t.Parallel() 1335 | 1336 | var tests = []struct { 1337 | param string 1338 | expected bool 1339 | }{ 1340 | {"", false}, 1341 | {"ABCD", false}, 1342 | {"A", false}, 1343 | {"AC", false}, 1344 | {"AP", false}, 1345 | {"GER", false}, 1346 | {"NU", true}, 1347 | {"DE", true}, 1348 | {"JP", true}, 1349 | {"JPN", false}, 1350 | {"ZWE", false}, 1351 | {"GER", false}, 1352 | {"DEU", false}, 1353 | } 1354 | for _, test := range tests { 1355 | actual := IsISO3166Alpha2(test.param) 1356 | if actual != test.expected { 1357 | t.Errorf("Expected IsISO3166Alpha2(%q) to be %v, got %v", test.param, test.expected, actual) 1358 | } 1359 | } 1360 | } 1361 | 1362 | func TestIsISO3166Alpha3(t *testing.T) { 1363 | t.Parallel() 1364 | 1365 | var tests = []struct { 1366 | param string 1367 | expected bool 1368 | }{ 1369 | {"", false}, 1370 | {"ABCD", false}, 1371 | {"A", false}, 1372 | {"AC", false}, 1373 | {"AP", false}, 1374 | {"NU", false}, 1375 | {"DE", false}, 1376 | {"JP", false}, 1377 | {"ZWE", true}, 1378 | {"JPN", true}, 1379 | {"GER", false}, 1380 | {"DEU", true}, 1381 | } 1382 | for _, test := range tests { 1383 | actual := IsISO3166Alpha3(test.param) 1384 | if actual != test.expected { 1385 | t.Errorf("Expected IsISO3166Alpha3(%q) to be %v, got %v", test.param, test.expected, actual) 1386 | } 1387 | } 1388 | } 1389 | 1390 | func TestIsIP(t *testing.T) { 1391 | t.Parallel() 1392 | 1393 | // Without version 1394 | var tests = []struct { 1395 | param string 1396 | expected bool 1397 | }{ 1398 | {"", false}, 1399 | {"127.0.0.1", true}, 1400 | {"0.0.0.0", true}, 1401 | {"255.255.255.255", true}, 1402 | {"1.2.3.4", true}, 1403 | {"::1", true}, 1404 | {"2001:db8:0000:1:1:1:1:1", true}, 1405 | {"300.0.0.0", false}, 1406 | } 1407 | for _, test := range tests { 1408 | actual := IsIP(test.param) 1409 | if actual != test.expected { 1410 | t.Errorf("Expected IsIP(%q) to be %v, got %v", test.param, test.expected, actual) 1411 | } 1412 | } 1413 | 1414 | // IPv4 1415 | tests = []struct { 1416 | param string 1417 | expected bool 1418 | }{ 1419 | {"", false}, 1420 | {"127.0.0.1", true}, 1421 | {"0.0.0.0", true}, 1422 | {"255.255.255.255", true}, 1423 | {"1.2.3.4", true}, 1424 | {"::1", false}, 1425 | {"2001:db8:0000:1:1:1:1:1", false}, 1426 | {"300.0.0.0", false}, 1427 | } 1428 | for _, test := range tests { 1429 | actual := IsIPv4(test.param) 1430 | if actual != test.expected { 1431 | t.Errorf("Expected IsIPv4(%q) to be %v, got %v", test.param, test.expected, actual) 1432 | } 1433 | } 1434 | 1435 | // IPv6 1436 | tests = []struct { 1437 | param string 1438 | expected bool 1439 | }{ 1440 | {"", false}, 1441 | {"127.0.0.1", false}, 1442 | {"0.0.0.0", false}, 1443 | {"255.255.255.255", false}, 1444 | {"1.2.3.4", false}, 1445 | {"::1", true}, 1446 | {"2001:db8:0000:1:1:1:1:1", true}, 1447 | {"300.0.0.0", false}, 1448 | } 1449 | for _, test := range tests { 1450 | actual := IsIPv6(test.param) 1451 | if actual != test.expected { 1452 | t.Errorf("Expected IsIPv6(%q) to be %v, got %v", test.param, test.expected, actual) 1453 | } 1454 | } 1455 | } 1456 | 1457 | func TestIsPort(t *testing.T) { 1458 | t.Parallel() 1459 | 1460 | var tests = []struct { 1461 | param string 1462 | expected bool 1463 | }{ 1464 | {"1", true}, 1465 | {"65535", true}, 1466 | {"0", false}, 1467 | {"65536", false}, 1468 | {"65538", false}, 1469 | } 1470 | 1471 | for _, test := range tests { 1472 | actual := IsPort(test.param) 1473 | if actual != test.expected { 1474 | t.Errorf("Expected IsPort(%q) to be %v, got %v", test.param, test.expected, actual) 1475 | } 1476 | } 1477 | } 1478 | 1479 | func TestIsDNSName(t *testing.T) { 1480 | t.Parallel() 1481 | 1482 | var tests = []struct { 1483 | param string 1484 | expected bool 1485 | }{ 1486 | {"localhost", true}, 1487 | {"localhost.local", true}, 1488 | {"localhost.localdomain.intern", true}, 1489 | {"-localhost", false}, 1490 | {"localhost.-localdomain", false}, 1491 | {"localhost.localdomain.-int", false}, 1492 | {"_localhost", false}, 1493 | {"localhost._localdomain", false}, 1494 | {"localhost.localdomain._int", false}, 1495 | {"lÖcalhost", false}, 1496 | {"localhost.lÖcaldomain", false}, 1497 | {"localhost.localdomain.üntern", false}, 1498 | {"漢字汉字", false}, 1499 | {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de", false}, 1500 | } 1501 | 1502 | for _, test := range tests { 1503 | actual := IsDNSName(test.param) 1504 | if actual != test.expected { 1505 | t.Errorf("Expected IsDNS(%q) to be %v, got %v", test.param, test.expected, actual) 1506 | } 1507 | } 1508 | } 1509 | 1510 | func TestIsDialString(t *testing.T) { 1511 | t.Parallel() 1512 | 1513 | var tests = []struct { 1514 | param string 1515 | expected bool 1516 | }{ 1517 | {"localhost.local:1", true}, 1518 | {"localhost.localdomain:9090", true}, 1519 | {"localhost.localdomain.intern:65535", true}, 1520 | {"127.0.0.1:30000", true}, 1521 | {"[::1]:80", true}, 1522 | {"[1200::AB00:1234::2552:7777:1313]:22", false}, 1523 | {"-localhost:1", false}, 1524 | {"localhost.-localdomain:9090", false}, 1525 | {"localhost.localdomain.-int:65535", false}, 1526 | {"localhost.loc:100000", false}, 1527 | {"漢字汉字:2", false}, 1528 | {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de:20000", false}, 1529 | } 1530 | 1531 | for _, test := range tests { 1532 | actual := IsDialString(test.param) 1533 | if actual != test.expected { 1534 | t.Errorf("Expected IsDialString(%q) to be %v, got %v", test.param, test.expected, actual) 1535 | } 1536 | } 1537 | } 1538 | 1539 | func TestIsMAC(t *testing.T) { 1540 | t.Parallel() 1541 | 1542 | var tests = []struct { 1543 | param string 1544 | expected bool 1545 | }{ 1546 | {"3D:F2:C9:A6:B3:4F", true}, 1547 | {"3D-F2-C9-A6-B3:4F", false}, 1548 | {"123", false}, 1549 | {"", false}, 1550 | {"abacaba", false}, 1551 | } 1552 | for _, test := range tests { 1553 | actual := IsMAC(test.param) 1554 | if actual != test.expected { 1555 | t.Errorf("Expected IsMAC(%q) to be %v, got %v", test.param, test.expected, actual) 1556 | } 1557 | } 1558 | } 1559 | 1560 | func TestFilePath(t *testing.T) { 1561 | t.Parallel() 1562 | 1563 | var tests = []struct { 1564 | param string 1565 | expected bool 1566 | osType int 1567 | }{ 1568 | {"c:\\" + strings.Repeat("a", 32767), true, Win}, //See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath 1569 | {"c:\\" + strings.Repeat("a", 32768), false, Win}, 1570 | {"c:\\path\\file (x86)\bar", true, Win}, 1571 | {"c:\\path\\file", true, Win}, 1572 | {"c:\\path\\file:exe", false, Unknown}, 1573 | {"C:\\", true, Win}, 1574 | {"c:\\path\\file\\", true, Win}, 1575 | {"c:/path/file/", false, Unknown}, 1576 | {"/path/file/", true, Unix}, 1577 | {"/path/file:SAMPLE/", true, Unix}, 1578 | {"/path/file:/.txt", true, Unix}, 1579 | {"/path", true, Unix}, 1580 | } 1581 | for _, test := range tests { 1582 | actual, osType := IsFilePath(test.param) 1583 | if actual != test.expected || osType != test.osType { 1584 | t.Errorf("Expected IsFilePath(%q) to be %v, got %v", test.param, test.expected, actual) 1585 | } 1586 | } 1587 | } 1588 | 1589 | func TestIsLatitude(t *testing.T) { 1590 | t.Parallel() 1591 | 1592 | var tests = []struct { 1593 | param string 1594 | expected bool 1595 | }{ 1596 | {"", false}, 1597 | {"-90.000", true}, 1598 | {"+90", true}, 1599 | {"47.1231231", true}, 1600 | {"+99.9", false}, 1601 | {"108", false}, 1602 | } 1603 | for _, test := range tests { 1604 | actual := IsLatitude(test.param) 1605 | if actual != test.expected { 1606 | t.Errorf("Expected IsLatitude(%q) to be %v, got %v", test.param, test.expected, actual) 1607 | } 1608 | } 1609 | } 1610 | 1611 | func TestIsLongitude(t *testing.T) { 1612 | t.Parallel() 1613 | 1614 | var tests = []struct { 1615 | param string 1616 | expected bool 1617 | }{ 1618 | {"", false}, 1619 | {"-180.000", true}, 1620 | {"180.1", false}, 1621 | {"+73.234", true}, 1622 | {"+382.3811", false}, 1623 | {"23.11111111", true}, 1624 | } 1625 | for _, test := range tests { 1626 | actual := IsLongitude(test.param) 1627 | if actual != test.expected { 1628 | t.Errorf("Expected IsLongitude(%q) to be %v, got %v", test.param, test.expected, actual) 1629 | } 1630 | } 1631 | } 1632 | 1633 | func TestIsSSN(t *testing.T) { 1634 | t.Parallel() 1635 | 1636 | var tests = []struct { 1637 | param string 1638 | expected bool 1639 | }{ 1640 | {"", false}, 1641 | {"00-90-8787", false}, 1642 | {"66690-76", false}, 1643 | {"191 60 2869", true}, 1644 | {"191-60-2869", true}, 1645 | } 1646 | for _, test := range tests { 1647 | actual := IsSSN(test.param) 1648 | if actual != test.expected { 1649 | t.Errorf("Expected IsSSN(%q) to be %v, got %v", test.param, test.expected, actual) 1650 | } 1651 | } 1652 | } 1653 | 1654 | func TestIsMongoID(t *testing.T) { 1655 | t.Parallel() 1656 | 1657 | var tests = []struct { 1658 | param string 1659 | expected bool 1660 | }{ 1661 | {"507f1f77bcf86cd799439011", true}, 1662 | {"507f1f77bcf86cd7994390", false}, 1663 | {"507f1f77bcf86cd79943901z", false}, 1664 | {"507f1f77bcf86cd799439011 ", false}, 1665 | {"", false}, 1666 | } 1667 | for _, test := range tests { 1668 | actual := IsMongoID(test.param) 1669 | if actual != test.expected { 1670 | t.Errorf("Expected IsMongoID(%q) to be %v, got %v", test.param, test.expected, actual) 1671 | } 1672 | } 1673 | } 1674 | 1675 | func TestIsSemver(t *testing.T) { 1676 | t.Parallel() 1677 | var tests = []struct { 1678 | param string 1679 | expected bool 1680 | }{ 1681 | {"v1.0.0", true}, 1682 | {"1.0.0", true}, 1683 | {"1.1.01", false}, 1684 | {"1.01.0", false}, 1685 | {"01.1.0", false}, 1686 | {"v1.1.01", false}, 1687 | {"v1.01.0", false}, 1688 | {"v01.1.0", false}, 1689 | {"1.0.0-alpha", true}, 1690 | {"1.0.0-alpha.1", true}, 1691 | {"1.0.0-0.3.7", true}, 1692 | {"1.0.0-0.03.7", false}, 1693 | {"1.0.0-00.3.7", false}, 1694 | {"1.0.0-x.7.z.92", true}, 1695 | {"1.0.0-alpha+001", true}, 1696 | {"1.0.0+20130313144700", true}, 1697 | {"1.0.0-beta+exp.sha.5114f85", true}, 1698 | {"1.0.0-beta+exp.sha.05114f85", true}, 1699 | {"1.0.0-+beta", false}, 1700 | {"1.0.0-b+-9+eta", false}, 1701 | {"v+1.8.0-b+-9+eta", false}, 1702 | } 1703 | for _, test := range tests { 1704 | actual := IsSemver(test.param) 1705 | if actual != test.expected { 1706 | t.Errorf("Expected IsSemver(%q) to be %v, got %v", test.param, test.expected, actual) 1707 | } 1708 | } 1709 | } 1710 | 1711 | func TestIsNegative(t *testing.T) { 1712 | t.Parallel() 1713 | 1714 | var tests = []struct { 1715 | param float64 1716 | expected bool 1717 | }{ 1718 | {0, false}, 1719 | {-1, true}, 1720 | {10, false}, 1721 | {3.14, false}, 1722 | {-96, true}, 1723 | {-10e-12, true}, 1724 | } 1725 | for _, test := range tests { 1726 | actual := IsNegative(test.param) 1727 | if actual != test.expected { 1728 | t.Errorf("Expected IsNegative(%q) to be %v, got %v", test.param, test.expected, actual) 1729 | } 1730 | } 1731 | } 1732 | 1733 | func TestIsNonNegative(t *testing.T) { 1734 | t.Parallel() 1735 | 1736 | var tests = []struct { 1737 | param float64 1738 | expected bool 1739 | }{ 1740 | {0, true}, 1741 | {-1, false}, 1742 | {10, true}, 1743 | {3.14, true}, 1744 | {-96, false}, 1745 | {-10e-12, false}, 1746 | } 1747 | for _, test := range tests { 1748 | actual := IsNonNegative(test.param) 1749 | if actual != test.expected { 1750 | t.Errorf("Expected IsNonNegative(%q) to be %v, got %v", test.param, test.expected, actual) 1751 | } 1752 | } 1753 | } 1754 | 1755 | func TestIsPositive(t *testing.T) { 1756 | t.Parallel() 1757 | 1758 | var tests = []struct { 1759 | param float64 1760 | expected bool 1761 | }{ 1762 | {0, false}, 1763 | {-1, false}, 1764 | {10, true}, 1765 | {3.14, true}, 1766 | {-96, false}, 1767 | {-10e-12, false}, 1768 | } 1769 | for _, test := range tests { 1770 | actual := IsPositive(test.param) 1771 | if actual != test.expected { 1772 | t.Errorf("Expected IsPositive(%q) to be %v, got %v", test.param, test.expected, actual) 1773 | } 1774 | } 1775 | } 1776 | 1777 | func TestIsNonPositive(t *testing.T) { 1778 | t.Parallel() 1779 | 1780 | var tests = []struct { 1781 | param float64 1782 | expected bool 1783 | }{ 1784 | {0, true}, 1785 | {-1, true}, 1786 | {10, false}, 1787 | {3.14, false}, 1788 | {-96, true}, 1789 | {-10e-12, true}, 1790 | } 1791 | for _, test := range tests { 1792 | actual := IsNonPositive(test.param) 1793 | if actual != test.expected { 1794 | t.Errorf("Expected IsNonPositive(%q) to be %v, got %v", test.param, test.expected, actual) 1795 | } 1796 | } 1797 | } 1798 | 1799 | func TestIsWhole(t *testing.T) { 1800 | t.Parallel() 1801 | 1802 | var tests = []struct { 1803 | param float64 1804 | expected bool 1805 | }{ 1806 | {0, true}, 1807 | {-1, true}, 1808 | {10, true}, 1809 | {3.14, false}, 1810 | {-96, true}, 1811 | {-10e-12, false}, 1812 | } 1813 | for _, test := range tests { 1814 | actual := IsWhole(test.param) 1815 | if actual != test.expected { 1816 | t.Errorf("Expected IsWhole(%q) to be %v, got %v", test.param, test.expected, actual) 1817 | } 1818 | } 1819 | } 1820 | 1821 | func TestIsNatural(t *testing.T) { 1822 | t.Parallel() 1823 | 1824 | var tests = []struct { 1825 | param float64 1826 | expected bool 1827 | }{ 1828 | {0, false}, 1829 | {-1, false}, 1830 | {10, true}, 1831 | {3.14, false}, 1832 | {96, true}, 1833 | {-10e-12, false}, 1834 | } 1835 | for _, test := range tests { 1836 | actual := IsNatural(test.param) 1837 | if actual != test.expected { 1838 | t.Errorf("Expected IsNatural(%q) to be %v, got %v", test.param, test.expected, actual) 1839 | } 1840 | } 1841 | } 1842 | 1843 | func TestIsInRange(t *testing.T) { 1844 | t.Parallel() 1845 | 1846 | var tests = []struct { 1847 | param float64 1848 | left float64 1849 | right float64 1850 | expected bool 1851 | }{ 1852 | {0, 0, 0, true}, 1853 | {1, 0, 0, false}, 1854 | {-1, 0, 0, false}, 1855 | {0, -1, 1, true}, 1856 | {0, 0, 1, true}, 1857 | {0, -1, 0, true}, 1858 | {0, 0, -1, true}, 1859 | {0, 10, 5, false}, 1860 | } 1861 | for _, test := range tests { 1862 | actual := IsInRange(test.param, test.left, test.right) 1863 | if actual != test.expected { 1864 | t.Errorf("Expected IsInRange(%q, %q, %q) to be %v, got %v", test.param, test.left, test.right, test.expected, actual) 1865 | } 1866 | } 1867 | } 1868 | 1869 | func TestIsMatches(t *testing.T) { 1870 | t.Parallel() 1871 | 1872 | var tests = []struct { 1873 | param1 string 1874 | param2 string 1875 | expected bool 1876 | }{ 1877 | {"123456789", "[0-9]+", true}, 1878 | {"abacada", "cab$", false}, 1879 | {"111222333", "((111|222|333)+)+", true}, 1880 | {"abacaba", "((123+]", false}, 1881 | } 1882 | for _, test := range tests { 1883 | actual := IsMatches(test.param1, test.param2) 1884 | if actual != test.expected { 1885 | t.Errorf("Expected IsMatches(%q,%q) to be %v, got %v", test.param1, test.param2, test.expected, actual) 1886 | } 1887 | } 1888 | } 1889 | 1890 | func TestIsStringLength(t *testing.T) { 1891 | t.Parallel() 1892 | 1893 | var tests = []struct { 1894 | value string 1895 | min string 1896 | max string 1897 | expected bool 1898 | }{ 1899 | {"123456", "0", "100", true}, 1900 | {"1239999", "0", "0", false}, 1901 | {"1239asdfasf99", "100", "200", false}, 1902 | {"1239999asdff29", "10", "30", true}, 1903 | {"あいうえお", "0", "5", true}, 1904 | {"あいうえおか", "0", "5", false}, 1905 | {"あいうえお", "0", "0", false}, 1906 | {"あいうえ", "5", "10", false}, 1907 | } 1908 | for _, test := range tests { 1909 | actual := IsStringLength(test.value, test.min, test.max) 1910 | if actual != test.expected { 1911 | t.Errorf("Expected IsStringLength(%s, %s, %s) to be %v, got %v", test.value, test.min, test.max, test.expected, actual) 1912 | } 1913 | } 1914 | } 1915 | -------------------------------------------------------------------------------- /patterns.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | import "regexp" 4 | 5 | // Basic regular expressions for validating strings 6 | const ( 7 | // Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" 8 | CreditCard string = "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$" 9 | ISBN10 string = "^(?:[0-9]{9}X|[0-9]{10})$" 10 | ISBN13 string = "^(?:[0-9]{13})$" 11 | UUID3 string = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$" 12 | UUID4 string = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" 13 | UUID5 string = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" 14 | UUID string = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" 15 | // Alpha string = "^[a-zA-Z]+$" 16 | // Alphanumeric string = "^[a-zA-Z0-9]+$" 17 | // Numeric string = "^[-+]?[0-9]+$" 18 | Int string = "^(?:[-+]?(?:0|[1-9][0-9]*))$" 19 | Float string = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$" 20 | Hexadecimal string = "^[0-9a-fA-F]+$" 21 | Hexcolor string = "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" 22 | RGBcolor string = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$" 23 | // ASCII string = "^[\x00-\x7F]+$" 24 | Multibyte string = "[^\x00-\x7F]" 25 | FullWidth string = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" 26 | HalfWidth string = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]" 27 | // Base64 string = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" 28 | // PrintableASCII string = "^[\x20-\x7E]+$" 29 | DataURI string = "^data:.+\\/(.+);base64$" 30 | Latitude string = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" 31 | Longitude string = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" 32 | DNSName string = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{1,62}){1}(.[a-zA-Z0-9]{1}[a-zA-Z0-9_-]{1,62})*$` 33 | URL string = `^((ftp|https?):\/\/)?(\S+(:\S*)?@)?((([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(([a-zA-Z0-9]+([-\.][a-zA-Z0-9]+)*)|((www\.)?))?(([a-z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-z\x{00a1}-\x{ffff}]{2,}))?))(:(\d{1,5}))?((\/|\?|#)[^\s]*)?$` 34 | SSN string = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` 35 | WinPath string = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$` 36 | UnixPath string = `^((?:\/[a-zA-Z0-9\.\:]+(?:_[a-zA-Z0-9\:\.]+)*(?:\-[\:a-zA-Z0-9\.]+)*)+\/?)$` 37 | Semver string = "^v?(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$" 38 | Cameling string = `[\p{L}\p{N}]+` 39 | ) 40 | 41 | // Used by IsFilePath func 42 | const ( 43 | // Unknown is unresolved OS type 44 | Unknown = iota 45 | // Win is Windows type 46 | Win 47 | // Unix is *nix OS types 48 | Unix 49 | ) 50 | 51 | // Regular expressions patterns 52 | var ( 53 | // rxEmail = regexp.MustCompile(Email) 54 | rxCreditCard = regexp.MustCompile(CreditCard) 55 | rxISBN10 = regexp.MustCompile(ISBN10) 56 | rxISBN13 = regexp.MustCompile(ISBN13) 57 | rxUUID3 = regexp.MustCompile(UUID3) 58 | rxUUID4 = regexp.MustCompile(UUID4) 59 | rxUUID5 = regexp.MustCompile(UUID5) 60 | rxUUID = regexp.MustCompile(UUID) 61 | // rxAlpha = regexp.MustCompile(Alpha) 62 | // rxAlphanumeric = regexp.MustCompile(Alphanumeric) 63 | // rxNumeric = regexp.MustCompile(Numeric) 64 | rxInt = regexp.MustCompile(Int) 65 | rxFloat = regexp.MustCompile(Float) 66 | rxHexadecimal = regexp.MustCompile(Hexadecimal) 67 | rxHexcolor = regexp.MustCompile(Hexcolor) 68 | rxRGBcolor = regexp.MustCompile(RGBcolor) 69 | // rxASCII = regexp.MustCompile(ASCII) 70 | // rxPrintableASCII = regexp.MustCompile(PrintableASCII) 71 | rxMultibyte = regexp.MustCompile(Multibyte) 72 | rxFullWidth = regexp.MustCompile(FullWidth) 73 | rxHalfWidth = regexp.MustCompile(HalfWidth) 74 | // rxBase64 = regexp.MustCompile(Base64) 75 | rxDataURI = regexp.MustCompile(DataURI) 76 | rxLatitude = regexp.MustCompile(Latitude) 77 | rxLongitude = regexp.MustCompile(Longitude) 78 | rxDNSName = regexp.MustCompile(DNSName) 79 | rxURL = regexp.MustCompile(URL) 80 | rxSSN = regexp.MustCompile(SSN) 81 | rxWinPath = regexp.MustCompile(WinPath) 82 | rxUnixPath = regexp.MustCompile(UnixPath) 83 | rxSemver = regexp.MustCompile(Semver) 84 | rxCameling = regexp.MustCompile(Cameling) 85 | ) 86 | -------------------------------------------------------------------------------- /to.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "strconv" 8 | "unicode" 9 | ) 10 | 11 | // ToString convert the input to a string. 12 | func ToString(obj interface{}) string { 13 | res := fmt.Sprintf("%v", obj) 14 | return string(res) 15 | } 16 | 17 | // ToJSON convert the input to a valid JSON string 18 | func ToJSON(obj interface{}) (string, error) { 19 | res, err := json.Marshal(obj) 20 | if err != nil { 21 | res = []byte("") 22 | } 23 | return string(res), err 24 | } 25 | 26 | // ToFloat convert the input string to a float, or 0.0 if the input is not a float. 27 | func ToFloat(str string) (float64, error) { 28 | res, err := strconv.ParseFloat(str, 64) 29 | if err != nil { 30 | res = 0.0 31 | } 32 | return res, err 33 | } 34 | 35 | // ToInt convert the input string to an integer, or 0 if the input is not an integer. 36 | func ToInt(str string) (int64, error) { 37 | res, err := strconv.ParseInt(str, 0, 64) 38 | if err != nil { 39 | res = 0 40 | } 41 | return res, err 42 | } 43 | 44 | // ToBoolean convert the input string to a boolean. 45 | func ToBoolean(str string) (bool, error) { 46 | res, err := strconv.ParseBool(str) 47 | if err != nil { 48 | res = false 49 | } 50 | return res, err 51 | } 52 | 53 | // ToCamelCase converts from underscore separated form to camel case form. 54 | func ToCamelCase(s string) string { 55 | byteSrc := []byte(s) 56 | chunks := rxCameling.FindAll(byteSrc, -1) 57 | for idx, val := range chunks { 58 | chunks[idx] = bytes.Title(val) 59 | } 60 | return string(bytes.Join(chunks, nil)) 61 | } 62 | 63 | // ToSnakeCase converts from camel case form to underscore separated form. 64 | func ToSnakeCase(s string) string { 65 | s = ToCamelCase(s) 66 | runes := []rune(s) 67 | length := len(runes) 68 | var out []rune 69 | for i := 0; i < length; i++ { 70 | out = append(out, unicode.ToLower(runes[i])) 71 | if i+1 < length && (unicode.IsUpper(runes[i+1]) && unicode.IsLower(runes[i])) { 72 | out = append(out, '_') 73 | } 74 | } 75 | 76 | return string(out) 77 | } 78 | -------------------------------------------------------------------------------- /to_test.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestToInt(t *testing.T) { 9 | tests := []string{"1000", "-123", "abcdef", "100000000000000000000000000000000000000000000"} 10 | expected := []int64{1000, -123, 0, 0} 11 | for i := 0; i < len(tests); i++ { 12 | result, _ := ToInt(tests[i]) 13 | if result != expected[i] { 14 | t.Log("Case ", i, ": expected ", expected[i], " when result is ", result) 15 | t.FailNow() 16 | } 17 | } 18 | } 19 | 20 | func TestToBoolean(t *testing.T) { 21 | tests := []string{"true", "1", "True", "false", "0", "abcdef"} 22 | expected := []bool{true, true, true, false, false, false} 23 | for i := 0; i < len(tests); i++ { 24 | res, _ := ToBoolean(tests[i]) 25 | if res != expected[i] { 26 | t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) 27 | t.FailNow() 28 | } 29 | } 30 | } 31 | 32 | func ExampleToBoolean() { 33 | fmt.Println(ToBoolean("True")) 34 | fmt.Println(ToBoolean("true")) 35 | fmt.Println(ToBoolean("1")) 36 | fmt.Println(ToBoolean("False")) 37 | fmt.Println(ToBoolean("false")) 38 | fmt.Println(ToBoolean("0")) 39 | // Output: 40 | // true 41 | // true 42 | // true 43 | // false 44 | // false 45 | // false 46 | } 47 | 48 | func toString(t *testing.T, test interface{}, expected string) { 49 | res := ToString(test) 50 | if res != expected { 51 | t.Log("Case ToString: expected ", expected, " when result is ", res) 52 | t.FailNow() 53 | } 54 | } 55 | 56 | func TestToString(t *testing.T) { 57 | toString(t, "str123", "str123") 58 | toString(t, 123, "123") 59 | toString(t, 12.3, "12.3") 60 | toString(t, true, "true") 61 | toString(t, 1.5+10i, "(1.5+10i)") 62 | // Sprintf function not guarantee that maps with equal keys always will be equal in string representation 63 | //toString(t, struct{ Keys map[int]int }{Keys: map[int]int{1: 2, 3: 4}}, "{map[1:2 3:4]}") 64 | } 65 | 66 | func TestToFloat(t *testing.T) { 67 | tests := []string{"", "123", "-.01", "10.", "string", "1.23e3", ".23e10"} 68 | expected := []float64{0, 123, -0.01, 10.0, 0, 1230, 0.23e10} 69 | for i := 0; i < len(tests); i++ { 70 | res, _ := ToFloat(tests[i]) 71 | if res != expected[i] { 72 | t.Log("Case ", i, ": expected ", expected[i], " when result is ", res) 73 | t.FailNow() 74 | } 75 | } 76 | } 77 | 78 | func TestToCamelCase(t *testing.T) { 79 | t.Parallel() 80 | 81 | var tests = []struct { 82 | param string 83 | expected string 84 | }{ 85 | {"a_b_c", "ABC"}, 86 | {"my_func", "MyFunc"}, 87 | {"1ab_cd", "1abCd"}, 88 | {"toUTFCamelCase", "ToUTFCamelCase"}, 89 | {"camel case", "CamelCase"}, 90 | {" camel case ", "CamelCase"}, 91 | {"!!!camel case====", "CamelCase"}, 92 | {"camel-case", "CamelCase"}, 93 | {"camel_case", "CamelCase"}, 94 | } 95 | for _, test := range tests { 96 | actual := ToCamelCase(test.param) 97 | if actual != test.expected { 98 | t.Errorf("Expected ToCamelCase(%q) to be %v, got %v", test.param, test.expected, actual) 99 | } 100 | } 101 | } 102 | 103 | func ExampleToCamelCase() { 104 | fmt.Println(ToCamelCase("camel case")) 105 | fmt.Println(ToCamelCase(" camel case ")) 106 | fmt.Println(ToCamelCase("!!!camel case====")) 107 | fmt.Println(ToCamelCase("camel-case")) 108 | fmt.Println(ToCamelCase("camel_case")) 109 | // Output: 110 | // CamelCase 111 | // CamelCase 112 | // CamelCase 113 | // CamelCase 114 | // CamelCase 115 | } 116 | 117 | func TestToSnakeCase(t *testing.T) { 118 | t.Parallel() 119 | 120 | var tests = []struct { 121 | param string 122 | expected string 123 | }{ 124 | {"a", "a"}, 125 | {"snake", "snake"}, 126 | {"A", "a"}, 127 | {"ID", "id"}, 128 | {"MOTD", "motd"}, 129 | {"Snake", "snake"}, 130 | {"SnakeTest", "snake_test"}, 131 | {"SnakeID", "snake_id"}, 132 | {"LinuxMOTD", "linux_motd"}, 133 | {"snake case", "snake_case"}, 134 | {" ! snake----- [ case", "snake_case"}, 135 | {"publicF", "public_f"}, 136 | {"RESTful", "restful"}, 137 | {"APIResponse", "apiresponse"}, 138 | {"simpleXML", "simple_xml"}, 139 | } 140 | for _, test := range tests { 141 | actual := ToSnakeCase(test.param) 142 | if actual != test.expected { 143 | t.Errorf("Expected ToSnakeCase(%q) to be %v, got %v", test.param, test.expected, actual) 144 | } 145 | } 146 | } 147 | 148 | func ExampleToSnakeCase() { 149 | fmt.Println(ToSnakeCase("SnakeCase")) 150 | fmt.Println(ToSnakeCase("snake case")) 151 | fmt.Println(ToSnakeCase(" snake case ")) 152 | fmt.Println(ToSnakeCase("!!!snake case====")) 153 | fmt.Println(ToSnakeCase("snake-case")) 154 | fmt.Println(ToSnakeCase("snake_case")) 155 | // Output: 156 | // snake_case 157 | // snake_case 158 | // snake_case 159 | // snake_case 160 | // snake_case 161 | // snake_case 162 | } 163 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package godash 2 | 3 | func addSegment(inrune, segment []rune) []rune { 4 | if len(segment) == 0 { 5 | return inrune 6 | } 7 | if len(inrune) != 0 { 8 | inrune = append(inrune, '_') 9 | } 10 | inrune = append(inrune, segment...) 11 | return inrune 12 | } 13 | -------------------------------------------------------------------------------- /utils_test.go: -------------------------------------------------------------------------------- 1 | package godash 2 | --------------------------------------------------------------------------------