如何使用自定义字母有效地构建随机字符串?

时间:2017-12-10 11:34:47

标签: java random

我的字母表中包含 c 字符,并希望使用该字母创建长度 n 的随机String

作为一个例子,让我们说字母表由字母a-w组成(所以 c = 23)和生成的{{1 s的长度应为 n = 67。

生成这样的String的直观但也很天真的方法可能如下所示:

String

虽然这有效,但我觉得我浪费了太多的熵。在这个例子中,我要求RNG n = 67次为另一个号码,而所有这些只是为了生成一个String alpha = "abcdefghijklmnopqrstuvw"; int c = alpha.length(); int n = 67; SecureRandom random = new SecureRandom(); StringBuilder sb = new StringBuilder(); for(int i = 0; i < n; i++) { int nextPosition = random.nextInt(c); sb.append(alpha.charAt(nextPosition)); } System.out.println(sb.toString());

  • 调用RNG a不会更有效(...熵保存) 更少的次数,并更好地利用返回 值?例如。使用该方法只调用一次RNG StringnextBytes(byte[] bytes)数组足够大 创建一个长度为67的byte
  • 但在后一种情况下,我不知道如何映射随机String 数组到所需的byte。如果一个角色有,那将很容易 大小为一个字节(或一个字节的倍数),因此 n = 67 I 可以向RNG询问67个随机String,然后直接映射 从数组中的每个byte到一个字符。但是,对于大小为 c = 23的字母,每个字符只有五个字节,甚至没有使用所有五个字节 - 如果我们枚举上面的所有字符,那么第一个字符{{ 1}}的二进制值为byte,而最后一个字符'a'的二进制值为00000(我选择的素数并非巧合)对于 n c ,它确实应该适用于任何情况。)

1 个答案:

答案 0 :(得分:1)

首先做一些数学运算:我们需要从23个字母的字母表中覆盖67个字符的最小字节数n是多少?将每个字节视为256个字母的字母表中的“字母”。然后

23 67 &lt; 256 名词

n&gt; 67 * ln(23)/ ln(256),可达37.8848或38字节。

你可以生成一个38字节的数组,从中构造BigInteger,并调用divideAndRemainder(23) 67次以获得单个字符索引和迭代中的下一个数字:

random.nextBytes(bytes);
BigInteger big = new BigInteger(bytes).abs();
BigInteger bigC = BigInteger.valueOf(c);
for (int i = 0 ; i != n ; i++) {
    BigInteger[] dr = big.divideAndRemainder(bigC);
    res[i] = alpha.charAt(dr[1].intValue());
    big = dr[0];
}
String result = new String(res);

Demo