We may desire to generate random strings or even sets of characters in order to perform some operations with strings in an application. We can choose a character at random from a set of characters, change the order of characters in a given string, or generate a random string. In Golang, with the help of the rand
package, we can easily write a custom function to generate a random string with the desired length.
Using rand function
Package rand
implements pseudo-random number generators unsuitable for security-sensitive work.
Random numbers are generated by a Source. Top-level functions, such as Float64 and Int, use a default shared Source that produces a deterministic sequence of values each time a program is run. Use the Seed function to initialize the default Source if different behavior is required for each run. The default Source is safe for concurrent use by multiple goroutines, but Sources created by NewSource are not.
This package's outputs might be easily predictable regardless of how it's seeded. For random numbers suitable for security-sensitive work, see the crypto/rand package.
For example, in the below example rand.Intn
 returns a random int
 n, 0 <= n < 100
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Print("Random number: ", rand.Intn(100))
}
Output:
Random number: 81
Method-1: Generate random string from pre-defined characters
The ideal is we randomly select characters from a given charset as many times as the set length of the output and combine them to form a random.
package main
import (
"fmt"
"math/rand"
"time"
)
// define the given charset, char only
var charset = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
// n is the length of random string we want to generate
func randStr(n int) string {
b := make([]byte, n)
for i := range b {
// randomly select 1 character from given charset
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
func main() {
// Seeding with the same value results in the same random sequence each run.
// For different numbers, seed with a different value, such as
// time.Now().UnixNano(), which yields a constantly-changing number.
rand.Seed(time.Now().UnixNano())
fmt.Println("First random string: ", randStr(10))
fmt.Println("Second random string: ", randStr(10))
fmt.Println("Third random string: ", randStr(20))
}
Output:
First random string: DpJdqMraoi
Second random string: HwfENfgprn
Third random string: APSsUQJNnVbXDbDuilpr
Explanation: Create a charset to define which characters will be in the string. Create a byte
list to contains all the characters of the string. In the for loop, we generate the n
(size of the output string) random characters and add them to the list. Selecting random characters is done by the rand.Intn()
function, which returns a random number between 0 and the length of the charset, then get a character from the charset
at this random index. Do this n
times and add to the result gives us a list contain n random character. Convert list of bytes to a string
So instead of:
var charset = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
we can use:
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Method-2: Generate random string using rand.Read()
Read is a helper function that calls Reader with syntax func Read(b []byte) (n int, err error). This example reads 10 cryptographically secure pseudorandom numbers from rand.Reader
and writes them to a byte slice.
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
For example:
package main
import (
"fmt"
"math/rand"
"time"
)
func randStr(length int) string {
rand.Seed(time.Now().UnixNano())
b := make([]byte, length)
// Read b number of numbers
rand.Read(b)
return fmt.Sprintf("%x", b)[:length]
}
func main() {
fmt.Println("First random string of fixed length: ", randStr(10))
fmt.Println("Second random string of fixed length: ", randStr(15))
fmt.Println("Third random string of fixed length: ", randStr(20))
}
Output:
First random string of fixed length: 0c204d3960
Second random string of fixed length: 0c204d39600fddd
Third random string of fixed length: 0c204d39600fddd3f1f2
Example-1: Generate random string with integers only
In this example we will generate random string containing numbers only:
package main
import (
"fmt"
"math/rand"
"time"
)
// define the given charset, char only
var number = []byte("0123456789")
// n is the length of random string we want to generate
func randStr(n int) string {
b := make([]byte, n)
for i := range b {
// randomly select 1 character from given charset
b[i] = number[rand.Intn(len(number))]
}
return string(b)
}
func main() {
// Seeding with the same value results in the same random sequence each run.
// For different numbers, seed with a different value, such as
// time.Now().UnixNano(), which yields a constantly-changing number.
rand.Seed(time.Now().UnixNano())
fmt.Println("Time run: ", time.Now().UnixNano())
fmt.Println("First random string: ", randStr(10))
fmt.Println("Second random string: ", randStr(10))
fmt.Println("Third random string: ", randStr(20))
}
Output:
Time run: 1663523354636371100
First random string: 7875183419
Second random string: 2768545022
Third random string: 47681351755701582659
Example-2: Generate random string with alphanumeric characters only
As discussed, we have to modify the byte list to meet the requirement:
package main
import (
"fmt"
"math/rand"
"time"
)
// define the given charset, char only
var charset = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
var number = []byte("0123456789")
var alphaNumeric = append(charset, number...)
// n is the length of random string we want to generate
func randStr(n int) string {
b := make([]byte, n)
for i := range b {
// randomly select 1 character from given charset
b[i] = alphaNumeric[rand.Intn(len(alphaNumeric))]
}
return string(b)
}
func main() {
// Seeding with the same value results in the same random sequence each run.
// For different numbers, seed with a different value, such as
// time.Now().UnixNano(), which yields a constantly-changing number.
rand.Seed(time.Now().UnixNano())
fmt.Println("Time run: ", time.Now().UnixNano())
fmt.Println("First random string: ", randStr(10))
fmt.Println("Second random string: ", randStr(10))
fmt.Println("Third random string: ", randStr(20))
}
Output:
Time run: 1663523245039802700
First random string: P3nG59rlng
Second random string: 8A9MU4aahB
Third random string: Frgfp92JbulJhHUbhdMM
Example-3: Pre-define custom requirement for random string
In this example we will select 1 uppercase, 1 lowercase, 1 number and 1 special character and randomly choose the remaining characters. After that, we will shuffle the order of bytes and return the string.
package main
import (
"fmt"
"math/rand"
"time"
)
func randStr() string {
var lower = []byte("abcdefghijklmnopqrstuvwxyz")
var upper = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var number = []byte("0123456789")
var special = []byte("~=+%^*/()[]{}/!@#$?|")
allChar := append(lower, upper...)
allChar = append(allChar, number...)
allChar = append(allChar, special...)
b := make([]byte, 12)
// select 1 upper, 1 lower, 1 number and 1 special
b[0] = lower[rand.Intn(len(lower))]
b[1] = upper[rand.Intn(len(upper))]
b[2] = number[rand.Intn(len(number))]
b[3] = special[rand.Intn(len(special))]
for i := 4; i < 12; i++ {
// randomly select 1 character from given charset
b[i] = allChar[rand.Intn(len(allChar))]
}
//shuffle character
rand.Shuffle(len(b), func(i, j int) {
b[i], b[j] = b[j], b[i]
})
return string(b)
}
func main() {
// Seeding with the same value results in the same random sequence each run.
// For different numbers, seed with a different value, such as
// time.Now().UnixNano(), which yields a constantly-changing number.
rand.Seed(time.Now().UnixNano())
fmt.Println("Time run: ", time.Now().UnixNano())
fmt.Println("First random string: ", randStr())
fmt.Println("Second random string: ", randStr())
fmt.Println("Third random string: ", randStr())
}
Output:
PS C:\Users\admin\Desktop\golang\src\main> go run .\milestone15.go Time run: 1663524606744377000 First random string: avr[oa4X^(2B Second random string: 2/7EB?5trI/z Third random string: k(vGv3$P+RgF PS C:\Users\admin\Desktop\golang\src\main> go run .\milestone15.go Time run: 1663524610066538700 First random string: z7I#1UkZeyCz Second random string: Vk0+5[H|2]C1 Third random string: 96E/4]dNDHDb
Summary
In this article, I demonstrated how to use the math.rand()
function to generate a random string of any length. If you want to limit or add new characters to the set from which the random string is made, modify the charset
variable.
References
https://pkg.go.dev/math/rand
https://pkg.go.dev/time#Time.UnixNano
https://pkg.go.dev/crypto/rand#Read
How to generate a random string of a fixed length in Go?