модуль 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.
Открытые методы экземпляров
Исходный код
# File lib/random/formatter.rb, line 367 def alphanumeric(n = nil, chars: ALPHANUMERIC) n = 16 if n.nil? choose(chars, n) end
Генерирует случайную строку из букв и цифр.
Аргумент n задаёт длину строки из букв и цифр, которая должна быть сгенерирована. Аргумент chars задаёт список символов, из которых будет состоять результат.
Если n не указан или равен nil, предполагается значение 16. В будущем оно может быть больше.
Результат может содержать символы A-Z, a-z и 0-9, если не указан аргумент chars.
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 114
def base64(n=nil)
[random_bytes(n)].pack("m0")
end Генерирует случайную строку в формате base64.
Аргумент n задаёт длину, в байтах, случайного числа, которое нужно сгенерировать. Длина результирующей строки составляет примерно 4/3 от n.
Если n не указан или равен nil, предполагается значение 16. В будущем оно может быть больше.
Результат может содержать символы A-Z, a-z, 0-9, “+”, “/” и “=”.
require 'random/formatter' Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A==" # or prng = Random.new prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
См. RFC 3548 для определения формата base64.
Исходный код
# File lib/random/formatter.rb, line 92
def hex(n=nil)
random_bytes(n).unpack1("H*")
end Генерирует случайную строку в шестнадцатеричном формате.
Аргумент n задаёт длину, в байтах, случайного числа, которое нужно сгенерировать. Длина результирующей шестнадцатеричной строки в два раза больше n.
Если n не указан или равен nil, предполагается значение 16. В будущем оно может быть больше.
Результат может содержать символы 0-9 и a-f.
require 'random/formatter' Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485" # or prng = Random.new prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
Генерирует отформатированное случайное число из исходных случайных байтов. См. Random#rand.
Исходный код
# File lib/random/formatter.rb, line 71 def random_bytes(n=nil) n = n ? n.to_int : 16 gen_random(n) end
Генерирует случайную двоичную строку.
Аргумент 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"
Исходный код
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;
} Генерирует отформатированное случайное число из исходных случайных байтов. См. Random#rand.
Исходный код
# 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 Генерирует случайную строку base64, безопасную для использования в URL.
Аргумент n задаёт длину, в байтах, случайного числа, которое нужно сгенерировать. Длина результирующей строки составляет примерно 4/3 от n.
Если 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=="
См. RFC 3548 для определения URL-безопасного формата base64.
Исходный код
# File lib/random/formatter.rb, line 169
def uuid
ary = random_bytes(16)
ary.setbyte(6, (ary.getbyte(6) & 0x0f) | 0x40)
ary.setbyte(8, (ary.getbyte(8) & 0x3f) | 0x80)
ary.unpack("H8H4H4H4H12").join(?-)
end Генерирует случайный UUID версии 4 (универсальный уникальный идентификатор).
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"
UUID версии 4 полностью случайный (кроме версии). Он не содержит значимой информации, такой как MAC-адреса, метки времени и т. д.
Результат содержит 122 случайных бита (15.25 случайных байтов).
См. RFC9562 для подробной информации об UUIDv4.
Исходный код
# File lib/random/formatter.rb, line 246
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 Генерирует случайный UUID версии 7 (универсальный уникальный идентификатор).
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"
UUID версии 7 начинается с наименее значимых 48 битов 64-битного Unix-времени (миллисекунды с начала эпохи) и заполняет оставшиеся биты случайными данными, исключая биты версии и варианта.
Это позволяет упорядочить UUID версии 7 по времени создания. Упорядоченные по времени UUID могут использоваться для лучшей локализации индексов базы данных для недавно вставленных записей, что может существенно улучшить производительность по сравнению с вставками случайных данных.
Результат содержит 74 случайных бита (9.25 случайных байтов).
Обратите внимание, что этот метод не может быть воспроизводимым, потому что его вывод включает не только случайные биты, но и метку времени.
См. RFC9562 для подробностей о UUIDv7.
Монотонность
UUIDv7 по умолчанию имеет точность в миллисекундах, поэтому несколько UUID, созданных в течение одной миллисекунды, не выдаются в монотонно возрастающем порядке. Чтобы создавать UUID, которые упорядочены по времени с точностью до долей миллисекунды, может быть добавлено до 12 бит дополнительного времени с помощью extra_timestamp_bits. Дополнительная точность метки времени достигается за счёт случайных битов. Установка extra_timestamp_bits: 12 обеспечивает точность ~244 нс, но только 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 312
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 Генерирует строку, случайным образом выбирая символы из массива.
Аргумент source определяет массив символов, из которого генерируется строка. Аргумент n определяет длину, в символах, генерируемой строки.
Результат может содержать любые символы из массива source.
require 'random/formatter' prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron" prng.choose([*'0'..'9'], 5) #=> "27309"
Исходный код
# File lib/random/formatter.rb, line 294
def gen_random(n)
self.bytes(n)
end Внутренний интерфейс для Random; Генерирует случайные данные объёмом n байт.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.