首頁 > 軟體

go語言生成亂數和隨機字串的實現方法

2021-12-08 16:00:08

生成亂數

亂數的生成是電腦科學的一個研究領域,同時也是一種藝術。這是因為計算機是純粹的邏輯機器,所以使用計算機生成亂數異常困難!

你可以用 math/rand 包來生成亂數。開始生成亂數之前首先需要一個種子,種子用於整個過程的初始化,它相當重要。因為如果你每次都用同樣的種子初始化,那麼就總是會得到相同的亂數序列。這意味著每個人都可以重新生成同一個序列,那這個序列就根本不能再算是隨機的了!

我們將用來生成亂數的程式名為 randomNumbers.go,下面分成四個部分進行介紹。這個程式需要幾個引數,分別是生成亂數的下限、生成亂數的上限、生成亂數的數量。如果你還用了第四個命令引數,那麼程式會將它作為亂數生成器的種子。在測試的時候,你就可以再次使用這個引數生成相同的數列。

程式的第一部分如下所示:

package main

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

func random(min, max int) int {
    return rand.Intn(max-min) + min
}

random() 函數完成了所有的工作,它通過根據指定的範圍呼叫 rand.Intn() 生成亂數。

這個命令列程式的第二部分如下:

func main() {
    MIN := 0
    MAX := 100
    TOTAL := 100
    SEED := time.Now().Unix()

    arguments := os.Args

這一部分對程式中將會用到的變數進行了初始化。

randomNumbers.go 的第三部分包含如下的 Go 程式碼:

    switch len(arguments) {
    case 2:
        fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED")
        MIN, _ = strconv.Atoi(arguments[1])
        MAX = MIN + 100
    case 3:
        fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED")
        MIN, _ = strconv.Atoi(arguments[1])
        MAX, _ = strconv.Atoi(arguments[2])
    case 4:
        fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED")
        MIN, _ = strconv.Atoi(arguments[1])
        MAX, _ = strconv.Atoi(arguments[2])
        TOTAL, _ = strconv.Atoi(arguments[3])
    case 5:
        MIN, _ = strconv.Atoi(arguments[1])
        MAX, _ = strconv.Atoi(arguments[2])
        TOTAL, _ = strconv.Atoi(arguments[3])
        SEED, _ = strconv.ParseInt(arguments[4], 10, 64)
    default:
        fmt.Println("Using default values!")
    }

switch 程式碼塊背後的邏輯相對簡單:根據命令列引數的數量決定程式中的引數是使用預設的預設值還是使用使用者提供的值。為了簡化程式,strconv.Atoi() 和 strconv.ParseInt() 函數返回的 error 引數使用下劃線字元接收,然後被忽略。如果是商業程式就千萬不能忽略 strconv.Atoi() 和 strconv.ParseInt() 函數返回的 error 引數!

最後,使用 strconv.ParseInt() 對 SEED 變數賦新的值是因為 rand.Seed() 函數要求的引數型別是 int64。strconv.ParseInt() 的第一個引數是要解析的字串,第二個引數是輸出數的基數,第三個引數是輸出數的位數。由於我們想要生成的是一個 64 位的十進位制整數,所以使用 10 作為基數,使用 64 作為位數。注意,如果你想解析無符號的整數的話應該使用 strconv.ParseUint() 函數代替。

randomNumbers.go 的最後一部分是如下的 Go 程式碼:

    rand.Seed(SEED)
    for i := 0; i < TOTAL; i++ {
        myrand := random(MIN, MAX)
        fmt.Print(myrand)
        fmt.Print(" ")
    }
    fmt.Println()
}

除了使用 Unix 時間戳作為亂數生成器的種子,你還可以使用 /dev/random 這個系統裝置。你可以在第 8 章「Go Unix系統程式設計」中瞭解 /dev/random 的相關內容。

執行 randomNumbers.go 將會生成如下輸出:

$ go run randomNumbers.go
75 69 15 75 62 67 64 8 73 1 83 92 7 34 8 70 22 58 38 8 54 91 65 1 50 76 5 82 61 90 10 38 40 63 6 28 51 54 49 27 52 92 76 35 44 9 66 76 90 10 29 22 20 83 33 92 80 50 62 26 19 45 56 75 40 30 97 23 87 10 43 11 42 65 80 82 25 53 27 51 99 88 53 36 37 73 52 61 4 81 71 57 30 72 51 55 62 63 79
$ go run randomNumbers.go 1 3 2
Usage: ./randomNumbers MIN MAX TOTAL SEED
1 1 
$ go run randomNumbers.go 1 3 2
Usage: ./randomNumbers MIN MAX TOTAL SEED
2 2
$ go run randomNumbers.go 1 5 10 10
3 1 4 4 1 1 4 4 4 3
$ go run randomNumbers.go 1 5 10 10
3 1 4 4 1 1 4 4 4 3

如果你對亂數生成真的很有興趣,那麼你應該先讀一下 Donald E.Knuth 寫的 The Art of Computer Programming (Addison-Wesley Professional, 2011) 的第二卷。

如果需要用 Go 生成更安全的亂數的話,你可以使用 crypto/rand 包。這個包中實現了滿足密碼學安全的偽亂數生成器。你可以在 https://golang.org/pkg/crypto/rand/ 檔案頁面瞭解更多關於 crypto/rand 包的資訊。

生成隨機字串

一旦你知道了計算機是如何呈現出單個字元,從亂數過渡到隨機字串就不難了。這一節將會介紹如何使用前一節中 randomNumbers.go 的程式碼生成難以猜出的密碼。用於完成這個任務的 Go 程式叫做 generatePassword.go,下面將分四個部分進行介紹。這個程式只需要一個命令列引數,就是你需要生成的密碼的長度。

generatePassword.go 的第一部分包含如下的 Go 程式碼:

package main

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

func random(min, max int) int {
    return rand.Intn(max-min) + min
}

generatePassword.go 的第二個程式碼段如下:

func main() {
    MIN := 0
    MAX := 94
    SEED := time.Now().Unix()
    var LENGTH int64 = 8

    arguments := os.Arg

我們只想得到可列印的 ASCII 字元,所以對生成亂數的範圍進行了限制。ASCII 字元表中可列印的字元一共有 94 個。這意味著該程式生成的亂數的範圍應該是從 0 到 94 且不包括 94。

generatePassword.go 的第三個程式碼段如下:

    switch len(arguments) {
    case 2:
        LENGTH, _ = strconv.ParseInt(os.Args[1], 10, 64)
    default:
        fmt.Println("Using default values!")
    }

       rand.Seed(SEED)

generatePassword.go 的最後一部分如下:

    startChar := "!"
    var i int64 = 1
    for {
        myRand := random(MIN, MAX)
        newChar := string(startChar[0] + byte(myRand))
        fmt.Print(newChar)
        if i == LENGTH {
            break
        }
        i++
    }
    fmt.Println()
}

startChar 引數儲存了這個程式可以生成的第一個 ASCII 字元,也就是十進位制 ASCII 值為 33 的感嘆號。已知該程式生成的亂數小於 94,可以計算出生成的最大的 ASCII 值為 93 + 33,等於 126,也就是 ~ 的 ASCII 值。下面的輸出是含有十進位制數值的 ASCII 字元表:

The decimal set:

  0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel
  8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si
 16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb
 24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us
 32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '
 40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /
 48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7
 56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?
 64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G
 72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O
 80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W
 88  X    89  Y    90  Z    91  [    92      93  ]    94  ^    95  _
 96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g
104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o
112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w
120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del

在你最喜歡的 Unix shell 中輸入 man ascii 就能生成易讀的 ASCII 字元表。

執行 generatePassword.go 並傳入合適的命令列引數將生成如下輸出:

$ go run generatePassword.go
Using default values!
ugs$5mv1
$ go run generatePassword.go
Using default values!
PA/[email protected]?
$ go run generatePassword.go 20
HBR+=3UA'[email protected]|o
$ go run generatePassword.go 20
XLcr|R{*pX/::'t2u^T'

到此這篇關於go語言生成亂數和隨機字串的實現方法的文章就介紹到這了,更多相關go語言生成亂數和隨機字串內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com