在Go中,我只想要一个随机字符串(大写或小写),没有数字。最快最简单的方法是什么?


当前回答

两个可能的选项(当然可能有更多):

您可以使用crypto/rand包,它支持读取随机字节数组(来自/dev/urandom),并面向加密随机生成。见http://golang.org/pkg/crypto/rand/#example_Read。它可能比普通的伪随机数生成慢。 取一个随机数,用md5或类似的方法进行哈希。

其他回答

如果需要选择是否大写,我通常会这样做

func randomString(length int, upperCase bool) string {
    rand.Seed(time.Now().UnixNano())

    var alphabet string

    if upperCase {
        alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    } else {
        alphabet = "abcdefghijklmnopqrstuvwxyz"
    }

    var sb strings.Builder

    l := len(alphabet)

    for i := 0; i < length; i++ {
        c := alphabet[rand.Intn(l)]
        sb.WriteByte(c)
    }

    return sb.String()
}

如果不需要大写字母,就像这样

func randomString(length int) string {
        rand.Seed(time.Now().UnixNano())

        var alphabet string = "abcdefghijklmnopqrstuvwxyz"
        var sb strings.Builder

        l := len(alphabet)

        for i := 0; i < length; i++ {
                c := alphabet[rand.Intn(l)]
                sb.WriteByte(c)
        }

        return sb.String()
}

如果您愿意向允许的字符池中添加一些字符,您可以使代码与任何通过io.Reader提供随机字节的东西一起工作。这里我们使用的是crypto/rand。

// len(encodeURL) == 64. This allows (x <= 265) x % 64 to have an even
// distribution.
const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

// A helper function create and fill a slice of length n with characters from
// a-zA-Z0-9_-. It panics if there are any problems getting random bytes.
func RandAsciiBytes(n int) []byte {
    output := make([]byte, n)

    // We will take n bytes, one byte for each character of output.
    randomness := make([]byte, n)

    // read all random
    _, err := rand.Read(randomness)
    if err != nil {
        panic(err)
    }

    // fill output
    for pos := range output {
        // get random item
        random := uint8(randomness[pos])

        // random % 64
        randomPos := random % uint8(len(encodeURL))

        // put into output
        output[pos] = encodeURL[randomPos]
    }

    return output
}

如果您想要加密安全的随机数,并且确切的字符集是灵活的(例如,base64就可以),那么您可以根据所需的输出大小精确计算所需的随机字符的长度。

64进制文本比256进制文本长1/3。(2^8 vs 2^6;8位/6位= 1.333比率)

import (
    "crypto/rand"
    "encoding/base64"
    "math"
)

func randomBase64String(l int) string {
    buff := make([]byte, int(math.Ceil(float64(l)/float64(1.33333333333))))
    rand.Read(buff)
    str := base64.RawURLEncoding.EncodeToString(buff)
    return str[:l] // strip 1 extra character we get from odd length results
}

注意:你也可以使用RawStdEncoding,如果你喜欢+和/字符-和_

如果你想要十六进制,以16为底比以256为底长2倍。(2^8 vs 2^4;8位/4位= 2x比例)

import (
    "crypto/rand"
    "encoding/hex"
    "math"
)


func randomBase16String(l int) string {
    buff := make([]byte, int(math.Ceil(float64(l)/2)))
    rand.Read(buff)
    str := hex.EncodeToString(buff)
    return str[:l] // strip 1 extra character we get from odd length results
}

但是,如果您的字符集使用base256到baseN编码器,则可以将其扩展到任何任意字符集。你可以用同样的大小计算需要多少位来表示你的字符集。任何任意字符集的比率计算是:ratio = 8 / log2(len(字符集)))。

虽然这两种解决方案都是安全的,简单的,应该是快速的,并且不会浪费您的加密熵池。

这是一个游乐场,它适用于任何尺寸。https://play.golang.org/p/_yF_xxXer0Z

func Rand(n int) (str string) {
    b := make([]byte, n)
    rand.Read(b)
    str = fmt.Sprintf("%x", b)
    return
}

另一个版本,灵感来自于生成密码在JavaScript加密:

package main

import (
    "crypto/rand"
    "fmt"
)

var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-"

func shortID(length int) string {
    ll := len(chars)
    b := make([]byte, length)
    rand.Read(b) // generates len(b) random bytes
    for i := 0; i < length; i++ {
        b[i] = chars[int(b[i])%ll]
    }
    return string(b)
}

func main() {
    fmt.Println(shortID(18))
    fmt.Println(shortID(18))
    fmt.Println(shortID(18))
}