我试图在Go中生成一个随机字符串,这是我到目前为止编写的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package main import ( "bytes" "fmt" "math/rand" "time" ) func main() { fmt.Println(randomString(10)) } func randomString(l int) string { var result bytes.Buffer var temp string for i := 0; i < l; { if string(randInt(65, 90)) != temp { temp = string(randInt(65, 90)) result.WriteString(temp) i++ } } return result.String() } func randInt(min int, max int) int { rand.Seed(time.Now().UTC().UnixNano()) return min + rand.Intn(max-min) } |
我的执行速度很慢。 使用
- " if string(randInt(65,90))!= temp {"看起来像是您试图增加额外的安全性,但是,事情之间偶然发生了同样的事情。 通过这样做,您实际上可能在降低熵。
- 作为附带说明,无需在" time.Now()。UTC()。UnixNano()"中转换为UTC。 Unix时间是从Epoch开始计算的,Epoch始终是UTC。
- 您应该设置一次种子,只能设置一次,并且绝不能超过一次。 好吧,如果您的应用程序可以运行数天,则可以每天设置一次。
- 您应该播种一次。 我想" Z"可能永远不会出现,我猜呢? 因此,我更喜欢使用开始索引包含和结束索引排除。
每次设置相同的种子,您将获得相同的序列。因此,当然,如果您将种子设置为快速循环中的时间,则可能会多次调用相同的种子。
就您而言,在您调用
对于所有伪随机库,您只需设置一次种子,例如在初始化程序时,除非您特别需要重现给定的序列(通常仅用于调试和单元测试)。
之后,您只需调用
将
还请注意,我认为您可以简化字符串的构建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package main import ( "fmt" "math/rand" "time" ) func main() { rand.Seed(time.Now().UTC().UnixNano()) fmt.Println(randomString(10)) } func randomString(l int) string { bytes := make([]byte, l) for i := 0; i < l; i++ { bytes[i] = byte(randInt(65, 90)) } return string(bytes) } func randInt(min int, max int) int { return min + rand.Intn(max-min) } |
- 感谢您的解释,我认为这需要每次播种。
-
您也可以将
rand.Seed(...) 添加到功能init() 中。init() 在main() 之前被自动调用。请注意,您不需要从main() 调用init() ! - @Jabba对。我的回答尽可能简单,离问题不太远,但是您的观察是正确的。
- 非常精确的解释。
- 请注意,到目前为止,尚未发布任何答案都不能以加密安全的方式初始化种子。根据您的应用程序,这可能根本不重要,或者可能导致灾难性故障。
-
您编写的randInt函数不包括max。应该是:
return min + rand.Intn(max - min + 1) - @DomenicD。这是标准做法。您不会找到任何不排除最大范围的标准随机值函数。
- 在这里,亲爱的互联网陌生人,有一些假互联网点,您已经真正解决了问题。应该指出,这在OAuth方案中非常有用。
-
无论如何,@ IngoBlechschmidt
mathrand 都不是加密安全的。如果这是必需的,则应使用cryptorand 。
我不明白为什么人们在播种时间价值。以我的经验,这从来不是一个好主意。例如,虽然系统时钟可能以纳秒表示,但系统的时钟精度不是纳秒。
该程序不应在Go操场上运行,但是如果您在计算机上运行该程序,则可以粗略估算出可以期望的精度类型。我看到约1000000 ns的增量,所以1毫秒的增量。那是20位未使用的熵。一直以来,高位大多是恒定的。
这对您很重要,程度会有所不同,但是您只需使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import ( crypto_rand"crypto/rand" "encoding/binary" math_rand"math/rand" ) func init() { var b [8]byte _, err := crypto_rand.Read(b[:]) if err != nil { panic("cannot seed math/rand package with cryptographically secure random number generator") } math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:]))) } |
作为附带说明,但与您的问题有关。您可以使用此方法创建自己的
- 这个答案很不为人知。特别是对于可能在一秒钟内运行多次的命令行工具,这是必须做的。谢谢
只是为了后代而已:有时候使用初始字符集字符串生成随机字符串可能会更好。如果该字符串应该由人工手动输入,则很有用;排除0,O,1和l可以帮助减少用户错误。
1 2 3 4 5 6 7 8 9 10 | var alpha ="abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" // generates a random string of fixed size func srand(size int) string { buf := make([]byte, size) for i := 0; i < size; i++ { buf[i] = alpha[rand.Intn(len(alpha))] } return string(buf) } |
我通常将种子设置在
-
据我正确理解,在
rand.Intn(len(alpha)-1) 中不需要有-1 。这是因为rand.Intn(n) 总是返回小于n 的数字??(换句话说:从零到n-1 (包括零))。 -
@snap是正确的;实际上,在
len(alpha)-1 中包含-1 可以确保序列中从不使用数字9。 - 还应注意,排除0(零)是个好主意,因为您将字节片转换为字符串,这导致0变为空字节。例如,尝试创建一个中间为0字节的文件,看看会发生什么。
好吧,为什么这么复杂!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package main import ( "fmt" "math/rand" "time" ) func main() { rand.Seed( time.Now().UnixNano()) var bytes int for i:= 0 ; i < 10 ; i++{ bytes = rand.Intn(6)+1 fmt.Println(bytes) } //fmt.Println(time.Now().UnixNano()) } |
这是基于dystroy的代码,但符合我的需要。
死了六个(rands int
1 2 3 4 5 | func randomInt (min int , max int ) int { var bytes int bytes = min + rand.Intn(max) return int(bytes) } |
上面的功能是完全一样的。
我希望这些信息有用。
-
这将始终以相同的顺序(如果多次调用)以相同的顺序返回,这在我看来并不是很随机。查看实时示例:play.golang.org/p/fHHENtaPv5
3 5 2 5 4 2 5 6 3 1 - @ThomasModeneis:那是因为他们在操场上假时间。
- 谢谢@ofavre,那个假时间真的让我很头疼。
-
在调用
rand.Intn() 之前,您仍然需要播种,否则,每次运行程序时,总会得到相同的数字。 -
var bytes int 有什么原因吗?将上面的bytes = rand.Intn(6)+1 更改为bytes := rand.Intn(6)+1 有什么区别?他们俩似乎都为我工作,出于某种原因,其中之一不是最理想的吗?
如果您的目的只是生成一个随机数的字符串,那么我认为没有必要将它与多个函数调用复杂化或每次都重置种子。
最重要的步骤是在实际运行
这是创建随机数字符串的示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package main import ( "fmt" "math/rand" "time" ) func main(){ rand.Seed(time.Now().UnixNano()) var s string for i:=0;i<10;i++{ s+=fmt.Sprintf("%d",rand.Intn(7)) } fmt.Printf(s) } |
我使用Sprintf的原因是因为它允许简单的字符串格式设置。
同样,在
这是十亿分之一秒,两次获得相同种子的机会是多少。
无论如何,感谢您的帮助,这是我基于所有输入的最终解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package main import ( "math/rand" "time" ) func init() { rand.Seed(time.Now().UTC().UnixNano()) } // generates a random string func srand(min, max int, readable bool) string { var length int var char string if min < max { length = min + rand.Intn(max-min) } else { length = min } if readable == false { char ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" } else { char ="ABCDEFHJLMNQRTUVWXYZabcefghijkmnopqrtuvwxyz23479" } buf := make([]byte, length) for i := 0; i < length; i++ { buf[i] = char[rand.Intn(len(char)-1)] } return string(buf) } // For testing only func main() { println(srand(5, 5, true)) println(srand(5, 5, true)) println(srand(5, 5, true)) println(srand(5, 5, false)) println(srand(5, 7, true)) println(srand(5, 10, false)) println(srand(5, 50, true)) println(srand(5, 10, false)) println(srand(5, 50, true)) println(srand(5, 10, false)) println(srand(5, 50, true)) println(srand(5, 10, false)) println(srand(5, 50, true)) println(srand(5, 4, true)) println(srand(5, 400, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) println(srand(6, 5, true)) } |
-
回复:
what are the chances of getting the exact the exact same [nanosecond] twice? 很好。这一切都取决于golang运行时实现的内部精度。即使单位是纳秒,最小的增量也可能是毫秒或什至秒。
由于golang api的更改而导致的小更新,请省略.UTC():
time.Now()。UTC()。UnixNano()-> time.Now()。UnixNano()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import ( "fmt" "math/rand" "time" ) func main() { rand.Seed(time.Now().UnixNano()) fmt.Println(randomInt(100, 1000)) } func randInt(min int, max int) int { return min + rand.Intn(max-min) } |