Как создать случайную буквенно-цифровую строку с помощью Erlang?
Я пытаюсь создать случайный буквенно-цифровой идентификатор с Erlang.
Я наивно пробовал crypto:strong_rand_bytes(Bytes)
генерировать случайный двоичный файл, а затем использовал этот двоичный файл, который был создан с помощью <<"my_unique_random_id">>
- который не работал, потому что случайные биты не обязательно являются допустимой строкой UTF-8, правильно?
Ну, я искал другие варианты в документах erlang и в других местах, но ничего не нашел. Может ли кто-нибудь указать мне на решение?
Ответы
Ответ 1
Это может зависеть от случайности, в которой вы нуждаетесь. Erlang crypto
Модуль производит сильные случайные данные, чем модуль random
(смотрите также [Эрл-вопросы] Yaws безопасности бдительные - Yaws 1,93 и этот вопрос). Если вы хотите использовать strong_rand_bytes
для генерации идентификатора, возможно, получить его base64 может быть достаточно:
> base64:encode(crypto:strong_rand_bytes(Bytes)).
В случае необходимости вы можете включить это в список.
Ответ 2
Согласно Генерация случайных строк в Erlang, для генерации строки определенной длины из определенного набора символов требуется всего несколько строк Erlang.
get_random_string(Length, AllowedChars) ->
lists:foldl(fun(_, Acc) ->
[lists:nth(random:uniform(length(AllowedChars)),
AllowedChars)]
++ Acc
end, [], lists:seq(1, Length)).
Сообщение в блоге содержит поэтапное объяснение кода. Посмотрите на комментарии для нескольких советов по оптимизации.
Ответ 3
Я подготовил небольшой модуль для этого
Также он использует crypto:rand_uniform/2
, но не устарел random:uniform
module(cloud_rnd).
-export([rnd_chars/1, rnd_numbers/1, rnd_chars_numbers/1]).
rnd_chars(L) -> get_rnd(L, chars).
rnd_numbers(L) -> get_rnd(L, numbers).
rnd_chars_numbers(L) -> get_rnd(L, chars_numbers).
get_rnd(L, chars) -> gen_rnd(L, "abcdefghijklmnopqrstuvwxyz");
get_rnd(L, numbers) -> gen_rnd(L, "1234567890");
get_rnd(L, chars_numbers) -> gen_rnd(L, "abcdefghijklmnopqrstuvwxyz1234567890").
gen_rnd(Length, AllowedChars) ->
MaxLength = length(AllowedChars),
lists:foldl(
fun(_, Acc) -> [lists:nth(crypto:rand_uniform(1, MaxLength), AllowedChars)] ++ Acc end,
[], lists:seq(1, Length)
).
Ответ 4
Проблема с ответами на различные вопросы "Мне нужны случайные строки" (на любом языке) - это почти все решения, использующие неверную спецификацию, а именно длину строки. Сами вопросы редко показывают, почему нужны случайные строки, но я смело предполагаю, что они должны использоваться в качестве идентификаторов, которые должны быть уникальными.
Существует два ведущих способа получить строго уникальные строки: детерминистически (что не случайно) и хранить/сравнивать (что является обременительным). Что делать? Отбросьте призрак. Идите с вероятностной уникальностью. То есть, примите, что есть (хотя и небольшой) риск того, что ваши строки не будут уникальными. Здесь полезно понимание вероятности столкновения и энтропии.
Поэтому я перефразирую свое смелое предположение, поскольку вам нужно некоторое количество идентификаторов с небольшим риском повторения. В качестве конкретного примера предположим, что вам нужно 5 миллионов идентификаторов с риском повторения менее 1 триллиона. Итак, какая длина строки вам нужна? Ну, этот вопрос указан ниже, поскольку он зависит от используемых символов. Но что более важно, он ошибался. Вам нужна спецификация энтропии строк, а не их длина.
Здесь EntropyString может помочь.
Bits = entropy_string:bits(5.0e6, 1.0e12).
83.37013046707142
entropy_string:random_string(Bits).
<<"QDrjGQFGgGjJ4t9r2">>
Существуют и другие предопределенные наборы символов, и вы можете также указать свои собственные символы (хотя по соображениям эффективности поддерживаются только наборы с полномочиями в 2 символа). И, самое главное, риск повторения в указанном числе строк является явным. Больше не догадывается длина строки.
Ответ 5
randchar(N) ->
randchar(N, []).
randchar(0, Acc) ->
Acc;
randchar(N, Acc) ->
randchar(N - 1, [random:uniform(26) + 96 | Acc]).
Ответ 6
Вы можете использовать функцию uef_bin:random_latin_binary/2
отсюда: https://github.com/DOBRO/uef-lib#uef_binrandom_latin_binary2
Bin = uef_bin:random_latin_binary(Length, any)
И затем, если вам нужен тип string()
:
String = erlang:binary_to_list(Bin)