繁体   English   中英

唯一的字符串ID生成器算法

[英]unique string ID gererator algorithm

我正在阅读一个开源项目aventrix / jnanoid ,我听不懂mask和代码中的step

public static String randomNanoId(final Random random, final char[] alphabet, final int size) {

    if (random == null) {
        throw new IllegalArgumentException("random cannot be null.");
    }

    if (alphabet == null) {
        throw new IllegalArgumentException("alphabet cannot be null.");
    }

    if (alphabet.length == 0 || alphabet.length >= 256) {
        throw new IllegalArgumentException("alphabet must contain between 1 and 255 symbols.");
    }

    if (size <= 0) {
        throw new IllegalArgumentException("size must be greater than zero.");
    }

    final int mask = (2 << (int) Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1;
    final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);

    final StringBuilder idBuilder = new StringBuilder();

    while (true) {

        final byte[] bytes = new byte[step];
        random.nextBytes(bytes);

        for (int i = 0; i < step; i++) {

            final int alphabetIndex = bytes[i] & mask;

            if (alphabetIndex < alphabet.length) {
                idBuilder.append(alphabet[alphabetIndex]);
                if (idBuilder.length() == size) {
                    return idBuilder.toString();
                }
            }

        }

    }

}

在循环中,我们尝试在每次循环迭代中选择字母表的随机成员(字母)。 请注意,这在给定的循环迭代中可能会失败,因为我们可以获得的索引大于字母表的长度。 我们通过创建随机字节数组来选择字母。 然后,我们只使用每个随机字节的足够位,以确保我们可以选择字母表中的任何字母。 因此,如果我们的字母有两个字符,则一个位就足够了,因为它可以具有值0或1。如果我们的字母有9个字符,则需要四个位,因为三个位只能表示8个值(0-7)。 这就是面具。 我们掩盖了随机字节的后四位,并将它们用作字母表的索引。 因此,如果我们的随机字节为11000110,那么在我的示例中,我们将低四位(0110)用于9个字符的字母。 0110是十进制的6,因此我们在字符数组的索引6处选择字母。 现在您可以看到它如何失败。 如果我们的随机字节是01001101,那么我们将屏蔽1011(即十进制的13),它超出了9个字母的结尾。 如前所述,使用该算法设置掩码的代码可确保它足够长以覆盖整个字母,但是不能防止它太长。

我不得不说,步骤对我而言似乎有些武断。 如果您查看循环步骤,则是我们试图获取长度大小随机字符串的字节数。 我们已经看到,单个循环迭代可能无法选择字母,因此步幅需要大于大小。 多长时间取决于掩码相对于我们的字母长度的多少,因此乘以mask / alphabet.length是有意义的。 尽管如此,我们仍然不能选择足够多的随机字母,因此我们将其提高了1.6左右。 当然,我们仍然会失败(我们所有的随机字节都可能指向超出字母表末尾的字母),这就是为什么在其中拥有while(true)的原因:如果失败,我们将再次尝试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM