与[a-zA-Z0-9]字符串类似:
na1dopW129T0anN28udaZ
或十六进制字符串:
8c6f78ac23b4a7b8c0182d
我想说的是2K以上的字符。
答案 0 :(得分:22)
您可以使用Go包uniuri生成随机字符串(或查看源代码以了解它们是如何进行的)。你会想要使用:
func NewLen(length int) string
NewLen返回提供长度的新随机字符串,由标准字符组成。
或者,要指定使用的字符集:
func NewLenChars(length int, chars []byte) string
答案 1 :(得分:21)
这在我的盒子上大约200MBps。有明显的改进空间。
type randomDataMaker struct {
src rand.Source
}
func (r *randomDataMaker) Read(p []byte) (n int, err error) {
for i := range p {
p[i] = byte(r.src.Int63() & 0xff)
}
return len(p), nil
}
您只需使用io.CopyN
即可生成所需的字符串。显然你可以在路上或其他任何地方调整字符集。
关于这个模型的好处是它只是一个io.Reader
所以你可以使用它制作任何东西。
测试如下:
func BenchmarkRandomDataMaker(b *testing.B) {
randomSrc := randomDataMaker{rand.NewSource(1028890720402726901)}
for i := 0; i < b.N; i++ {
b.SetBytes(int64(i))
_, err := io.CopyN(ioutil.Discard, &randomSrc, int64(i))
if err != nil {
b.Fatalf("Error copying at %v: %v", i, err)
}
}
}
在我的2.2GHz i7的一个核心上:
BenchmarkRandomDataMaker 50000 246512 ns/op 202.83 MB/s
修改强>
自从我编写基准测试以来,我认为我会做一些明显的改进(不经常调用随机)。有了1/8的rand调用,它的运行速度提高了大约4倍,尽管这是一个很大的丑陋:
新版本:
func (r *randomDataMaker) Read(p []byte) (n int, err error) {
todo := len(p)
offset := 0
for {
val := int64(r.src.Int63())
for i := 0; i < 8; i++ {
p[offset] = byte(val & 0xff)
todo--
if todo == 0 {
return len(p), nil
}
offset++
val >>= 8
}
}
panic("unreachable")
}
新基准:
BenchmarkRandomDataMaker 200000 251148 ns/op 796.34 MB/s
编辑2
将转换中的掩码取出为字节,因为它是多余的。快点好了:
BenchmarkRandomDataMaker 200000 231843 ns/op 862.64 MB/s
(这比实际工作叹息更容易
)编辑3
今天在irc中出现了,所以我发布了一个库。此外,我的实际基准测试工具虽然对相对速度有用,但在报告中并不够准确。
我创建了randbo,您可以重复使用它来生成随机流,无论您需要它们。
答案 2 :(得分:15)
这实际上有点偏向于集合中的前8个字符(因为255不是len(alphanum)
的倍数),但这将使你在那里大部分时间。
import (
"crypto/rand"
)
func randString(n int) string {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
var bytes = make([]byte, n)
rand.Read(bytes)
for i, b := range bytes {
bytes[i] = alphanum[b % byte(len(alphanum))]
}
return string(bytes)
}
答案 3 :(得分:1)
在这里,Evan Shaw的回答重新开始,没有偏向于字符串的前8个字符。请注意,它使用了大量昂贵的big.Int
操作,所以可能不是那么快!答案虽然非常强大,但仍然非常强大。
它使用rand.Int
制作一个完全正确大小len(alphanum) ** n
的整数,然后进行有效的基本转换为基础len(alphanum)
。
几乎可以肯定有一个更好的算法,它将涉及保留一个小得多的余数,并根据需要添加随机字节。这将摆脱昂贵的长整数运算。
import (
"crypto/rand"
"fmt"
"math/big"
)
func randString(n int) string {
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
symbols := big.NewInt(int64(len(alphanum)))
states := big.NewInt(0)
states.Exp(symbols, big.NewInt(int64(n)), nil)
r, err := rand.Int(rand.Reader, states)
if err != nil {
panic(err)
}
var bytes = make([]byte, n)
r2 := big.NewInt(0)
symbol := big.NewInt(0)
for i := range bytes {
r2.DivMod(r, symbols, symbol)
r, r2 = r2, r
bytes[i] = alphanum[symbol.Int64()]
}
return string(bytes)
}
答案 4 :(得分:0)
如果您想生成加密安全随机字符串,建议您查看this page。这是一个辅助函数,它从操作系统的随机源中读取n
个随机字节,然后使用这些字节对其进行base64编码。请注意,由于base64,字符串长度将大于n
。
package main
import(
"crypto/rand"
"encoding/base64"
"fmt"
)
func GenerateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func GenerateRandomString(s int) (string, error) {
b, err := GenerateRandomBytes(s)
return base64.URLEncoding.EncodeToString(b), err
}
func main() {
token, _ := GenerateRandomString(32)
fmt.Println(token)
}
答案 5 :(得分:-3)
我做了一些基准测试,Dustin的randbo包是我见过的最快的。我把它搞砸了并进行了一些优化,所以它现在更快了:GitHub