用Go生成指定长度的随机字符串


=Start=

搜索关键字:

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, "ixyzero.com")
    io.WriteString(h, t.String())
    passwd := fmt.Sprintf("%x", h.Sum(nil))
    return passwd
}
参考链接:

=EOF=

,

《 “用Go生成指定长度的随机字符串” 》 有 12 条评论

  1. 一款 Go 语言开发的 UUID 生成服务
    https://github.com/dreamans/guuid
    `
    Guuid使用了服务器主机名、运行的进程ID、时间戳、随机数、时序元素等一系列元素来保证生成UUID的唯一性。

    UUID 16 bytes, 构成:
    4 bytes 主机名&进程ID
    4 bytes 时间戳
    4 bytes 计数器
    4 bytes 随机数
    `

  2. Go语言中[]byte和string类型相互转换时的性能分析和优化
    https://pengrl.com/p/31544/
    https://syslog.ravelin.com/byte-vs-string-in-go-d645b67ca7ff
    `
    我们在使用Go语言时,经常涉及到[]byte和string两种类型间的转换。本篇文章将讨论转换时的开销,Go编译器在一些特定场景下对转换做的优化,以及在高性能场景下,我们自己如何做相应的优化。

    []byte其实就是byte类型的切片,对应的底层结构体定义如下(在runtime/slice.go文件中)

    string对应的底层结构体定义如下(在runtime/string.go文件中)
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注