How to generate a random string in Go

Created
Modified

Using rand.Int63 Function

Int63 returns a non-negative pseudo-random 63-bit integer as an int64 from the default Source.

package main

import (
  "fmt"
  "math/rand"
  "time"
)

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func RandStringByLenth(n int) string {
  b := make([]byte, n)
  for i := range b {
    b[i] = letters[rand.Int63()%int64(len(letters))]
  }
  return string(b)
}

func main() {
  // Don't forget
  rand.Seed(time.Now().UTC().UnixNano())

  for range "012345" {
    s := RandStringByLenth(6)
    fmt.Println(s)
  }

}
GjwtZy
wZotMg
qRKVLB
RDQtvQ
RRbTrB
gzMuMm

Don't forget about the rand.Seed(), otherwise you got the same string every first time launch.

Masking

We can maintain the equal distribution of letters by using only as many of the lowest bits of the random number as many is required to represent the number of letters. So here is the solution:

package main

import (
  "fmt"
  "math/rand"
  "time"
)

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
  letterIdxBits = 6
  letterIdxMask = 1<<letterIdxBits - 1
  letterIdxMax  = 63 / letterIdxBits
)

func RandStringByLenth(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(letters) {
      b[i] = letters[idx]
      i--
    }
    cache >>= letterIdxBits
    remain--
  }
  return string(b)
}

func main() {
  // Don't forget
  rand.Seed(time.Now().UTC().UnixNano())

  for range "012345" {
    s := RandStringByLenth(6)
    fmt.Println(s)
  }

}
SADUwS
ufPPAG
eNmPcJ
JMFEtV
NHkRrN
gOlDuC

Using base64 Function

If you want cryptographically secure random numbers, and the exact charset is flexible (say, base64 is fine), you can calculate exactly what the length of random characters you need from the desired output size.

package main

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

func RandStringByBase64(n int) string {
  buff := make([]byte, int(math.Ceil(float64(n)/float64(1.33333333333))))
  rand.Read(buff)
  str := base64.RawURLEncoding.EncodeToString(buff)
  return str[:n]
}

func main() {

  for range "012345" {
    s := RandStringByBase64(6)
    fmt.Println(s)
  }

}
QnPVHr
mTA0nZ
h4HPrV
Yj7ZS2
TF8jo9
KKqM5_

Related Tags