module 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=="
Определение base64 см. в RFC 3548.
# 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=="
Определение base64, безопасной для URL, см. в RFC 3548.
# 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 (Universally Unique IDentifier — универсальный уникальный идентификатор).
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 случайного байта).
Подробнее о UUIDv4 см. в RFC9562.
# 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 (Universally Unique IDentifier — универсальный уникальный идентификатор).
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 по времени создания. Упорядоченные по Time UUID можно использовать для повышения локальности индексов базы данных при добавлении новых записей, что может значительно повысить производительность по сравнению со вставкой случайных данных.
Результат содержит 74 случайных бита (9,25 случайного байта).
Обратите внимание, что этот метод не может быть воспроизводимым, поскольку его результат включает не только случайные биты, но и временную метку.
Подробнее о UUIDv7 см. в RFC9562.
Монотонность
По умолчанию 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-сервером, настроенным на использование подхода «leap smear». Для синхронизации распределённых узлов также потребуется 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 задаёт длину генерируемой строки в символах.
Результат может содержать любые символы из исходного массива.
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–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.