有时候业务可能需要生成一个随机字符串,而我们希望包括的字符类型多一些,在go标准库中没有这样的包,不能开箱即用。
而基本字符在ASCII表中有确定的值,这些值在主流的编码系统中都是统一的,不分操作系统和编程语言,这一点确实给我们带来了便利。以下案例中使用的rand为标准数学库 math/rand。通过该编码值,我们可以轻松的不用复写这些字符,只需要知道属于它们的边界,在此基础上增加到某个位置,就可以获取到该字符。
import (
"math/rand"
)
1、生成一串随机的数字字符串
数字字符0-9在ASCII表中对应的十进制值是48-57,因此可以使用基于底数48,随机生成一个0-9之间的数字来随机取一个数字。
// Number 随机生成size个数字
func Number(size int) []byte {
if size <= 0 || size > 10 {
size = 10
}
warehouse := []int{48, 57}
result := make([]byte, 10)
rand.Seed(time.Now().UnixNano())
for i := 0; i < size; i++ {
result[i] = uint8(warehouse[0] + rand.Intn(9))
}
return result
}
2、生成一串小写字母
小写字母在ASCII表中对应的十进制数值是97-122。
// Lower 随机生成size个小写字母
func Lower(size int) []byte {
if size <= 0 || size > 26 {
size = 26
}
warehouse := []int{97, 122}
result := make([]byte, 26)
rand.Seed(time.Now().UnixNano())
for i := 0; i < size; i++ {
result[i] = uint8(warehouse[0] + rand.Intn(26))
}
return result
}
3、生成一串大写字母
小写字母在ASCII表中对应的十进制数值是65-90。
// Lower 随机生成size个小写字母
func Upper(size int) []byte {
if size <= 0 || size > 26 {
size = 26
}
warehouse := []int{65, 90}
result := make([]byte, 26)
rand.Seed(time.Now().UnixNano())
for i := 0; i < size; i++ {
result[i] = uint8(warehouse[0] + rand.Intn(26))
}
return result
}
4、按照需要的字符串长度和包含的数字,大小写字母数量,生成一个随机字符串
// Salt 生成一个盐值
func Salt(size int, number int, lower int, upper int) (string, error) {
// 参数校验
length := number + lower + upper
if size > length || length <= 0 {
return "", errors.New("非法的长度")
}
switch {
case number < 0, number > 10:
return "", errors.New("允许的数字范围0-10")
case lower < 0, upper < 0, lower > 26, upper > 26:
return "", errors.New("允许的字母范围0-26")
}
// 按需要生成字符串
var result string
if lower > 0 {
lowers := string(Lower(lower))
result += lowers
}
if number > 0 {
numbers := string(Number(number))
result += numbers
}
if upper > 0 {
uppers := string(Upper(upper))
result += uppers
}
return result, nil
}
5、使用方式
比如本地环境
package main
import (
"step/util"
"fmt"
)
func main() {
// 生成一个长度为6, 数字, 大小写字母分别有2位的字符串
s1, err := util.Salt(6, 2, 2, 2)
if err != nil {
fmt.Println(err)
}
fmt.Println(s1)
// 生成一个长度为8, 数字0个, 大写字母3个, 小写字母5个的字符串
s2, err := util.Salt(8, 0, 5, 3)
if err != nil {
fmt.Println(err)
}
fmt.Println(s2)
}
输出效果:
没有加入特殊字符,比如*,#等混淆,这些字符在ASCII表中都有对应的值。在输出盐时也没有打乱顺序,没有注意到标准库中是否有打乱字符串的函数,就没自己去实现了。