如何使用Erlang生成随机的字母数字字符串?

17

我正在尝试使用 Erlang 生成一个随机的字母数字ID。

我曾尝试过使用crypto:strong_rand_bytes(Bytes)来生成一个随机的二进制数据,并尝试将其像 <<"my_unique_random_id">> 一样使用。但是因为随机位不一定是有效的 UTF-8 字符串,所以这种方法行不通,对吗?

我在 Erlang 文档和其他地方寻找其他选项,但没有找到任何有用的信息。请问是否有人可以帮我找到解决方案呢?

6个回答

19

这可能取决于您所需的随机性。Erlang的crypto模块生成的随机数据比random模块更强(也可以参见[erlang-questions] Yaws security alert - Yaws 1.93此问题)。如果您想使用strong_rand_bytes生成ID,则获取其base64可能已足够:

> base64:encode(crypto:strong_rand_bytes(Bytes)).

如果需要的话,您可以将此转换为列表。


2
这段代码可以生成一个随机的二进制字符串,但不会创建包含字母和数字的字符串。该字符串可能包含特殊字符,如 += - Stratus3D
4
正则表达式来拯救:re:replace(base64:encode(crypto:strong_rand_bytes(Bytes)),"\\W","",[global,{return,binary}]). - Berzemus
Berzemus,"[global,{retu‌​rn,binary}]"的编码是非ASCII的。它无法编译。这些字符=="5b 67 6c 6f 62 61 6c 2c 7b 72 65 74 75 e2 80 8c e2 80 8b 72 6e 2c 62 69 6e 61 72 79 7d 5d",但在ASCII中,[global,{return,binary}]应该等于"5b 67 6c 6f 62 61 6c 2c 20 7b 72 65 74 75 72 6e 2c 20 62 69 6e 61 72 79 7d 5d"。此外,\W的编码不正确。 - Vans S

13
根据Generating random strings in Erlang,只需要使用几行Erlang代码即可从一组特定字符中生成指定长度的字符串。
get_random_string(Length, AllowedChars) ->
    lists:foldl(fun(_, Acc) ->
                        [lists:nth(random:uniform(length(AllowedChars)),
                                   AllowedChars)]
                            ++ Acc
                end, [], lists:seq(1, Length)).

这篇博客文章详细解释了代码的每一行。查看评论获取一些优化技巧。


2
为了在每次重新启动 Erlang VM 时获得不同的结果,您应该对随机数生成器进行种子化(示例:random:seed(erlang:now()))。有关更多信息,请查看此处此处 - Nuno Freitas
最好使用 crypto:rand_uniform(1, length(AllowedChars)) - cystbear
你的链接失效了。请尝试使用缓存结果。 - goncalotomas

6

我准备了一个小模块来完成这个任务

它还使用 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)
  ).

2
各种语言中“我需要随机字符串”的问题的回答存在一个问题,即几乎每个解决方案都使用了有缺陷的规范,即字符串长度。这些问题本身很少透露需要随机字符串的原因,但我大胆假设它们需要用作需要唯一标识符的标识符。
有两种主要方法可以获得严格唯一的字符串:确定性(不是随机的)和存储/比较(繁琐)。怎么办?放弃。改为使用概率唯一性。也就是说,接受您的字符串可能不唯一的一些(无论多小)风险。这就是理解碰撞概率和熵有帮助的地方。
所以我会重新表述我的大胆假设,即您需要一些具有重复风险的标识符数量。以具体的例子来说,假设您需要500万个标识符,其重复风险小于1兆分之一。那么你需要什么长度的字符串呢?好吧,这个问题是未指定的,因为它取决于使用的字符。但更重要的是,它是误导的。您需要的是字符串的熵的规范,而不是它们的长度。
这就是EntropyString可以帮助的地方。
Bits = entropy_string:bits(5.0e6, 1.0e12).
83.37013046707142
entropy_string:random_string(Bits).
<<"QDrjGQFGgGjJ4t9r2">>

还有其他预定义的字符集,您也可以指定自己的字符(但出于效率原因,仅支持具有2的幂字符的集合)。最重要的是,在指定的字符串数量中重复的风险是明确的。不再猜测字符串长度。


1
randchar(N) ->
   randchar(N, []).

randchar(0, Acc) ->
   Acc;
randchar(N, Acc) ->
   randchar(N - 1, [random:uniform(26) + 96 | Acc]).

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接