模組 Random::Formatter
亂數格式化器。¶ ↑
以多種方式格式化產生的亂數。當需要「random/formatter」時,會將多個方法新增到空的核心模組 Random::Formatter 中,讓它們可用作 Random 的實例和模組方法。
標準函式庫 SecureRandom
也會延伸模組,且以下說明的方法可用作其中的模組方法。
範例¶ ↑
產生亂數十六進位字串
require 'random/formatter' prng = Random.new prng.hex(10) #=> "52750b30ffbc7de3b362" prng.hex(10) #=> "92b15d6c8dc4beb5f559" prng.hex(13) #=> "39b290146bea6ce975c37cfc23" # or just Random.hex #=> "1aed0c631e41be7f77365415541052ee"
產生亂數 base64 字串
prng.base64(10) #=> "EcmTPZwWRAozdA==" prng.base64(10) #=> "KO1nIU+p9DKxGg==" prng.base64(12) #=> "7kJSM/MzBJI+75j8" Random.base64(4) #=> "bsQ3fQ=="
產生亂數二進位字串
prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301" prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337" Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"
產生英數字串
prng.alphanumeric(10) #=> "S8baxMJnPl" prng.alphanumeric(10) #=> "aOxAg8BAJe" Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"
產生 UUID
prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594" prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab" Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"
所有方法也可用於標準函式庫 SecureRandom
SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"
產生給定範圍內的亂數,如同 Random
所做
prng.random_number #=> 0.5816771641321361 prng.random_number(1000) #=> 485 prng.random_number(1..6) #=> 3 prng.rand #=> 0.5816771641321361 prng.rand(1000) #=> 485 prng.rand(1..6) #=> 3
常數
- ALPHANUMERIC
用於
alphanumeric
的預設字元清單。
公開實例方法
產生亂數英數字串。
引數 n 指定要產生的英數字串的長度(以字元為單位)。引數 chars 指定結果組成的字元清單。
如果未指定 n 或其為 nil,則假設為 16。未來可能會更大。
除非指定 chars,否則結果可能包含 A-Z、a-z 和 0-9。
require 'random/formatter' Random.alphanumeric #=> "2BuBuLf3WfSKyQbR" # or prng = Random.new prng.alphanumeric(10) #=> "i6K93NdqiH" Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952" # or prng = Random.new prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
# File lib/random/formatter.rb, line 368 def alphanumeric(n = nil, chars: ALPHANUMERIC) n = 16 if n.nil? choose(chars, n) end
產生一個隨機的 base64 字串。
參數 n 指定要產生的隨機數字的長度(以位元組為單位)。結果字串的長度約為 n 的 4/3。
如果未指定 n 或其為 nil,則假設為 16。未來可能會更大。
結果可能包含 A-Z、a-z、0-9、“+”、“/”和“=”。
require 'random/formatter' Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A==" # or prng = Random.new prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
有關 base64 的定義,請參閱 RFC 3548。
# File lib/random/formatter.rb, line 114 def base64(n=nil) [random_bytes(n)].pack("m0") end
產生一個隨機的十六進位字串。
參數 n 指定要產生的隨機數字的長度(以位元組為單位)。結果十六進位字串的長度是 n 的兩倍。
如果未指定 n 或其為 nil,則假設為 16。未來可能會更大。
結果可能包含 0-9 和 a-f。
require 'random/formatter' Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485" # or prng = Random.new prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
# File lib/random/formatter.rb, line 92 def hex(n=nil) random_bytes(n).unpack1("H*") end
從原始隨機位元組產生格式化的隨機數字。請參閱 Random#rand
。
產生一個隨機的二進位字串。
參數 n 指定結果字串的長度。
如果未指定 n 或 n 為 nil,則假設為 16。未來可能會更大。
結果可能包含任何位元組:“x00” - “xff”。
require 'random/formatter' Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6" # or prng = Random.new prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
# File lib/random/formatter.rb, line 71 def random_bytes(n=nil) n = n ? n.to_int : 16 gen_random(n) end
從原始隨機位元組產生格式化的隨機數字。請參閱 Random#rand
。
static VALUE rand_random_number(int argc, VALUE *argv, VALUE obj) { rb_random_t *rnd = try_get_rnd(obj); VALUE v = rand_random(argc, argv, obj, rnd); if (NIL_P(v)) v = rand_random(0, 0, obj, rnd); else if (!v) invalid_argument(argv[0]); return v; }
產生一個隨機的 URL 安全 base64 字串。
參數 n 指定要產生的隨機數字的長度(以位元組為單位)。結果字串的長度約為 n 的 4/3。
如果未指定 n 或其為 nil,則假設為 16。未來可能會更大。
布林參數 padding 指定填補。如果為 false 或 nil,則不產生填補。否則會產生填補。預設不產生填補,因為“=”可用作 URL 分隔符。
結果可能包含 A-Z、a-z、0-9、“-”和“_”。如果 padding 為 true,也會使用“=”。
require 'random/formatter' Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg" # or prng = Random.new prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg" prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ==" prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
有關 URL 安全 base64 的定義,請參閱 RFC 3548。
# File lib/random/formatter.rb, line 145 def urlsafe_base64(n=nil, padding=false) s = [random_bytes(n)].pack("m0") s.tr!("+/", "-_") s.delete!("=") unless padding s end
產生一個隨機的 v4 UUID(通用唯一識別碼)。
require 'random/formatter' Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594" Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab" # or prng = Random.new prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
版本 4 UUID 完全是隨機的(版本除外)。它不包含有意義的資訊,例如 MAC 位址、時間戳記等。
結果包含 122 個隨機位元(15.25 個隨機位元組)。
請參閱 RFC4122 以取得 UUID 的詳細資料。
# File lib/random/formatter.rb, line 169 def uuid ary = random_bytes(16).unpack("NnnnnN") ary[2] = (ary[2] & 0x0fff) | 0x4000 ary[3] = (ary[3] & 0x3fff) | 0x8000 "%08x-%04x-%04x-%04x-%04x%08x" % ary end
產生一個隨機 v7 UUID(通用唯一識別碼)。
require 'random/formatter' Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e" Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5" Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23" Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31" # |<--sorted-->| |<----- random ---->| # or prng = Random.new prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
第 7 版 UUID 以 64 位元 Unix 時間戳記(自紀元以來的毫秒數)的最後 48 個位元開始,並以隨機資料填滿其餘位元,但排除版本和變體位元。
這讓第 7 版 UUID 可以依據建立時間排序。時間
排序的 UUID 可用於改善資料庫索引中新插入記錄的區域性,與隨機資料插入相比,這可能會帶來顯著的效能提升。
結果包含 74 個隨機位元(9.25 個隨機位元組)。
請注意,此方法無法重製,因為其輸出不僅包含隨機位元,還包含時間戳記。
請參閱 draft-ietf-uuidrev-rfc4122bis 以取得 UUIDv7 的詳細資料。
單調性¶ ↑
UUIDv7 預設具有毫秒精度,因此在同一毫秒內建立的 UUID 並非以單調遞增順序發出。若要建立具有次毫秒精度的時間順序 UUID,可以使用 extra_timestamp_bits
最多新增 12 個位元的額外時間戳記。額外時間戳記精度是以犧牲隨機位元為代價。設定 extra_timestamp_bits: 12
可提供約 244ns 的精度,但僅有 62 個隨機位元(7.75 個隨機位元組)。
prng = Random.new Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) } # => ["0188d4c7-13da-74f9-8b53-22a786ffdd5a", "0188d4c7-13da-753b-83a5-7fb9b2afaeea", "0188d4c7-13da-754a-88ea-ac0baeedd8db", "0188d4c7-13da-7557-83e1-7cad9cda0d8d"] # |<--- sorted --->| |<-- random --->| Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) } # => ["0188d4c7-3333-7a95-850a-de6edb858f7e", "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order "0188d4c7-3333-7af9-87c3-8f612edac82e"] # |<--- sorted -->||<---- random --->|
系統時鐘的任何回滾都會破壞單調性。UUIDv7 基於 UTC,其中不包含閏秒,且可能會回滾時鐘。為避免此情況,系統時鐘可以與設定為使用「閏秒塗抹」方法的 NTP 伺服器同步。NTP 或 PTP 也會用於跨分散式節點同步。
並未實作計數器和其他用於更強單調性保證的機制。具有更嚴格需求的應用程式應遵循規格的 第 6.2 節。
# File lib/random/formatter.rb, line 247 def uuid_v7(extra_timestamp_bits: 0) case (extra_timestamp_bits = Integer(extra_timestamp_bits)) when 0 # min timestamp precision ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond) rand = random_bytes(10) rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant "%08x-%04x-%s" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), rand.unpack("H4H4H12").join("-") ] when 12 # max timestamp precision ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) .divmod(1_000_000) extra_bits = ns * 4096 / 1_000_000 rand = random_bytes(8) rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant "%08x-%04x-7%03x-%s" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), extra_bits, rand.unpack("H4H12").join("-") ] when (0..12) # the generic version is slower than the special cases above rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN") rand_mask_bits = 12 - extra_timestamp_bits ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) .divmod(1_000_000) "%08x-%04x-%04x-%04x-%04x%08x" % [ (ms & 0x0000_ffff_ffff_0000) >> 16, (ms & 0x0000_0000_0000_ffff), 0x7000 | ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) | rand_a & ((1 << rand_mask_bits) - 1), 0x8000 | (rand_b1 & 0x3fff), rand_b2, rand_b3 ] else raise ArgumentError, "extra_timestamp_bits must be in 0..12" end end
私人執行個體方法
從字元來源陣列隨機抽取字元來產生字串。
參數 source 指定要從中產生字串的字元陣列。參數 n 指定要產生的字串長度(以字元為單位)。
結果可能包含來源陣列中的任何字元。
require 'random/formatter' prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron" prng.choose([*'0'..'9'], 5) #=> "27309"
# File lib/random/formatter.rb, line 313 def choose(source, n) size = source.size m = 1 limit = size while limit * size <= 0x100000000 limit *= size m += 1 end result = ''.dup while m <= n rs = random_number(limit) is = rs.digits(size) (m-is.length).times { is << 0 } result << source.values_at(*is).join('') n -= m end if 0 < n rs = random_number(limit) is = rs.digits(size) if is.length < n (n-is.length).times { is << 0 } else is.pop while n < is.length end result.concat source.values_at(*is).join('') end result end
對 Random
的內部介面;產生隨機資料 n 位元組。
# File lib/random/formatter.rb, line 295 def gen_random(n) self.bytes(n) end