我正在尝试使用 Erlang 生成一个随机的字母数字 ID。我天真地尝试crypto:strong_rand_bytes(Bytes)
生成一个随机二进制文件,然后像创建它一样使用该二进制文件<<"my_unique_random_id">>
- 这不起作用,因为随机位不一定是有效的 UTF-8 字符串,对吧?
好吧,我在 erlang 文档和其他地方寻找其他选项,但我没有找到任何东西。有人可以指出我的解决方案吗?
这可能取决于您需要的随机性。Erlang 的crypto
模块产生比模块更强的随机数据random
(另见[erlang-questions] Yaws 安全警报 - Yaws 1.93和这个问题)。如果你想用来strong_rand_bytes
生成一个 ID,也许得到它的 base64 可能就足够了:
> base64:encode(crypto:strong_rand_bytes(Bytes)).
如果需要,您可以将其转换为列表。
根据在 Erlang 中生成随机字符串,只需几行 Erlang 即可从一组字符生成指定长度的字符串。
get_random_string(Length, AllowedChars) ->
lists:foldl(fun(_, Acc) ->
[lists:nth(random:uniform(length(AllowedChars)),
AllowedChars)]
++ Acc
end, [], lists:seq(1, Length)).
博客文章对代码进行了逐行解释。查看评论以获取一些优化技巧。
我已经准备了小模块,
它也使用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)
).
对各种“我需要随机字符串”问题(无论使用何种语言)的回答的问题是几乎每个解决方案都使用有缺陷的规范,即字符串长度。这些问题本身很少揭示为什么需要随机字符串,但我会大胆假设它们将用作需要唯一的标识符。
有两种主要的方法来获取严格唯一的字符串:确定性(不是随机的)和存储/比较(这是繁重的)。该怎么办?放弃鬼。改为使用概率唯一性。也就是说,接受您的字符串不是唯一的(尽管很小)风险。这就是理解碰撞概率和熵有帮助的地方。
因此,我将改写我的大胆假设,因为您需要一些重复风险很小的标识符。作为一个具体的例子,假设您需要 500 万个重复风险小于万亿分之一的 Id。那么你需要多长的字符串呢?好吧,这个问题没有详细说明,因为它取决于所使用的字符。但更重要的是,它被误导了。您需要的是字符串熵的规范,而不是它们的长度。
这就是EntropyString可以提供帮助的地方。
Bits = entropy_string:bits(5.0e6, 1.0e12).
83.37013046707142
entropy_string:random_string(Bits).
<<"QDrjGQFGgGjJ4t9r2">>
还有其他预定义的字符集,您也可以指定自己的字符(尽管出于效率原因,仅支持具有 2 个字符的幂的集)。最重要的是,在指定数量的字符串中重复的风险是明确的。不再猜测字符串长度。
randchar(N) ->
randchar(N, []).
randchar(0, Acc) ->
Acc;
randchar(N, Acc) ->
randchar(N - 1, [random:uniform(26) + 96 | Acc]).
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)