github.com/wuhuizuo/gomplate@v3.5.0+incompatible/random/random.go (about) 1 // Package random contains functions for generating random values 2 package random 3 4 import ( 5 "math" 6 "math/rand" 7 "regexp" 8 "time" 9 "unicode" 10 11 "github.com/pkg/errors" 12 ) 13 14 // Rnd - 15 var Rnd = rand.New(rand.NewSource(time.Now().UnixNano())) 16 17 // Default set, matches "[a-zA-Z0-9_.-]" 18 const defaultSet = "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" 19 20 // StringRE - Generate a random string that matches a given regular 21 // expression. Defaults to "[a-zA-Z0-9_.-]" 22 func StringRE(count int, match string) (r string, err error) { 23 var chars = []rune(defaultSet) 24 if match != "" { 25 chars, err = matchChars(match) 26 if err != nil { 27 return "", err 28 } 29 } 30 31 return rndString(count, chars) 32 } 33 34 // StringBounds returns a random string of characters with a codepoint 35 // between the lower and upper bounds. Only valid characters are returned 36 // and if a range is given where no valid characters can be found, an error 37 // will be returned. 38 func StringBounds(count int, lower, upper rune) (r string, err error) { 39 chars := filterRange(lower, upper) 40 if len(chars) == 0 { 41 return "", errors.Errorf("No printable codepoints found between U%#q and U%#q.", lower, upper) 42 } 43 return rndString(count, chars) 44 } 45 46 // produce a string containing a random selection of given characters 47 func rndString(count int, chars []rune) (string, error) { 48 s := make([]rune, count) 49 for i := range s { 50 s[i] = chars[Rnd.Intn(len(chars))] 51 } 52 return string(s), nil 53 } 54 55 func filterRange(lower, upper rune) []rune { 56 out := []rune{} 57 for r := lower; r <= upper; r++ { 58 if unicode.IsGraphic(r) { 59 out = append(out, r) 60 } 61 } 62 return out 63 } 64 65 func matchChars(match string) ([]rune, error) { 66 r, err := regexp.Compile(match) 67 if err != nil { 68 return nil, err 69 } 70 candidates := filterRange(0, unicode.MaxRune) 71 out := []rune{} 72 for _, c := range candidates { 73 if r.MatchString(string(c)) { 74 out = append(out, c) 75 } 76 } 77 return out, nil 78 } 79 80 // Item - 81 func Item(items []interface{}) (interface{}, error) { 82 if len(items) == 0 { 83 return nil, errors.Errorf("expected a non-empty array or slice") 84 } 85 if len(items) == 1 { 86 return items[0], nil 87 } 88 n := Rnd.Intn(len(items)) 89 return items[n], nil 90 } 91 92 // Number - 93 func Number(min, max int64) (int64, error) { 94 if min > max { 95 return 0, errors.Errorf("min must not be greater than max (was %d, %d)", min, max) 96 } 97 if min == math.MinInt64 { 98 min++ 99 } 100 if max-min >= (math.MaxInt64 >> 1) { 101 return 0, errors.Errorf("spread between min and max too high - must not be greater than 63-bit maximum (%d - %d = %d)", max, min, max-min) 102 } 103 return Rnd.Int63n(max-min+1) + min, nil 104 } 105 106 // Float - For now this is really just a wrapper around `rand.Float64` 107 func Float(min, max float64) (float64, error) { 108 return min + Rnd.Float64()*(max-min), nil 109 }