搜索关键字:
golang fixed length random string
参考解答:
常规的比较容易想到的方案(从目标字符集中随机选出N个字符组成字符串):
package main
import (
"fmt"
"math/rand"
)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func main() {
fmt.Println(randSeq(10))
}
从简单方案开始进行的一次优化历程:
// 将rune数组用byte数组替换
// var lettersB = []bytes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
// 将rune数组用字符串常量替换
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
// 用rand.Int63()替换rand.Intn()
func RandStringBytesRmndr(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
}
return string(b)
}
// 用掩码进行替换
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
func RandStringBytesMaskImpr(n int) string {
b := make([]byte, n)
// A rand.Int63() generates 63 random bits, enough for letterIdxMax letters!
for i, cache, remain := n-1, rand.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = rand.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(b)
}
上面的方法用的都是”math/rand”提供(伪)随机数,如果对随机性有高要求的话,可以用”crypto/rand”实现(速度相对来说会慢些):
// Reference: https://github.com/dchest/uniuri/blob/master/uniuri.go
package main
import (
"crypto/rand"
"fmt"
)
const (
StdLen = 16
UUIDLen = 20
)
var StdChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
// var AsciiChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~")
func main() {
fmt.Printf("%s\n", New())
fmt.Printf("%s\n", New())
fmt.Printf("%s\n", NewLen(8))
fmt.Printf("%s\n", NewLen(8))
}
func New() string {
return NewLenChars(StdLen, StdChars)
}
func NewLen(length int) string {
return NewLenChars(length, StdChars)
}
// NewLenChars returns a new random string of the provided length, consisting of the provided byte slice of allowed characters(maximum 256).
func NewLenChars(length int, chars []byte) string {
if length == 0 {
return ""
}
clen := len(chars)
if clen < 2 || clen > 256 {
panic("Wrong charset length for NewLenChars()")
}
maxrb := 255 - (256 % clen)
b := make([]byte, length)
r := make([]byte, length+(length/4)) // storage for random bytes.
i := 0
for {
if _, err := rand.Read(r); err != nil {
panic("Error reading random bytes: " + err.Error())
}
for _, rb := range r {
c := int(rb)
if c > maxrb {
continue // Skip this number to avoid modulo bias.
}
b[i] = chars[c%clen]
i++
if i == length {
return string(b)
}
}
}
}
还有一个比较偏门的方法就是用哈希值来表示随机字符串:
// create random passwd
func createPasswd() string {
t := time.Now()
h := md5.New()
io.WriteString(h, "crazyof.me")
io.WriteString(h, t.String())
passwd := fmt.Sprintf("%x", h.Sum(nil))
return passwd
}
原文链接:https://crazyof.me/blog/archives/2535.html