我需要生成一个包含6个alpha数字字符的保留代码,这在java中是随机且唯一的。
尝试使用UUID.randomuuid().toString()
,但是id太长,要求它应该只有6个字符。
有哪些可能的方法来实现这一点?
只是为了澄清,(因为这个问题被标记为重复)。我发现的其他解决方案是简单地生成随机字符,这在这种情况下是不够的。我需要合理地确保不会再次生成随机代码。
考虑使用hashids
库来生成整数(您的数据库id或其他随机整数,这可能更好)的加盐哈希。
Hashids hashids = new Hashids("this is my salt",6);
String id = hashids.encode(1, 2, 3);
long[] numbers = hashids.decode(id);
在字母数字字符集中有36个字符(0-9个数字+ a-z个字母)。有了6个位置,你得到366 = 2.176.782.336个不同的选项,这比231略大。
因此,您可以使用Unix time来创建唯一的ID。但是,您必须确保在同一秒内不会生成任何ID。
如果你不能保证这一点,你最终会在你的类中使用一个(同步的)计数器。此外,如果您想在JVM重启后存活下来,您应该保存当前值(例如保存到数据库、文件等,无论您有什么选项)。尽管它的名字,uid并不是唯一的。128位的碰撞是不可能发生的。对于6(小于32位),如果您只是散列内容或生成随机字符串,则很可能会发生冲突。
如果唯一性约束是必要的,那么您需要
- 生成随机的6个字符串
- 检查之前是否通过查询数据库生成了该字符串
- 如果你之前生成的,回到1
然后您将在输出上运行Base62(或至少Base 41)并删除填充字符以获得6个字符的输出。
如果是子字符串,则该值可能不是唯一的
更多信息请参见下面的类似链接生成仅8个字符的uuid
假设语料库是alpha数字字母的集合。a-zA-Z0-9
.
char[] corpus = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
我们可以使用SecureRandom
生成一个种子,它将根据操作系统向操作系统请求熵。这里的技巧是保持均匀分布,每个字节有255个值,但我们只需要大约62个值,所以我建议拒绝抽样。
int generated = 0;
int desired=6;
char[] result= new char[desired];
while(generated<desired){
byte[] ran = SecureRandom.getSeed(desired);
for(byte b: ran){
if(b>=0&&b<corpus.length){
result[generated] = corpus[b];
generated+=1;
if(generated==desired) break;
}
}
}
改进可以包括更智能地包装生成的值。
什么时候可以再来一次?让我们继续使用62和的语料库,假设的分布是完全随机的。这样的话,我们就有生日问题了。这就得到了N = 62^6的可能性。我们想找到n,其中重复的机会在10%左右。
p(r)= 1 - N!/(N^n (N-n)!)
使用维基百科页面给出的近似。
n = sqrt(-ln(0.9)2N)
这给了我们大约109000个数字,10%的概率。0.1%的概率需要10000个数字。
您可以尝试从生成的UUID中生成子字符串。
String uuid = UUID.randomUUID().toString();
System.out.println("uuid = " + uuid.substring(0,5);