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



我有一个带有一个 c 字符的字母,并希望用该字母创建长度 n 的随机 String s。/p>

作为示例,假设字母由字母 a-w(so so c = 23)组成,并且生成的 String s应具有 n的长度 = 67。

一种直观但又天真的生成这种String的方法可能看起来像这样:

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());

在工作时,我觉得自己浪费了太多的entophy 。在此示例中,我要问RNG n = 67次,而所有数字仅用于生成一个String

  • 呼叫rng a会不会更有效(...节省内存)次数要小得多,可以更好地利用返回的值?例如。该方法仅调用一次RNG一次 nextBytes(byte[] bytes)和一个byte阵列足够大创建一个长度为67的String
  • 但是在后一种情况下,我不知道如何映射随机byte数组到所需的String。如果一个角色有一个字节的大小(或一个字节的倍数),因此对于 n = 67 i可以向RNG询问67个随机byte S,然后直接映射从数组中的每个byte到一个字符。但是,使用大小 c = 23的字母,每个字符只有五个字节,甚至没有使用所有五个字节 - 如果我们从上方枚举所有字符,则第一个字符'a'具有00000的二进制值,而最后一个字符 'w'的二进制值为 10110(我选择了 n c 的素数并不是一个巧合,它确实应该无论如何工作)。

首先进行一些数学:最小的字节数字n是我们需要从23个字母字母中覆盖67个字符的字节的最小数字?考虑每个字节在256个字母中的"字母"。然后

23 67 &lt;256 n

n> 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

最新更新