Java 生成唯一且随机的六个字母数字代码的程序
Java program to generate a unique and random six alpha numeric code
我需要生成一个由 6 个字母数字字符组成的预订代码,该代码在 java 中是随机且唯一的。
尝试使用UUID.randomuuid().toString()
,但是id太长,要求只能是6个字符。
有哪些方法可以实现这一点?
澄清一下,(因为这个问题被标记为重复)。
我发现的其他解决方案只是简单地生成随机字符,这在这种情况下是不够的。我需要合理保证不再生成乱码
您可以尝试从生成的 UUID 中创建子字符串。
String uuid = UUID.randomUUID().toString();
System.out.println("uuid = " + uuid.substring(0,5);
如果你做一个子字符串,该值可能不是唯一的
有关更多信息,请参阅以下类似内容 link
Generating 8-character only UUIDs
考虑使用 hashids
库生成整数的加盐哈希值(您的数据库 ID 或其他可能更好的随机整数)。
Hashids hashids = new Hashids("this is my salt",6);
String id = hashids.encode(1, 2, 3);
long[] numbers = hashids.decode(id);
尽管名称如此,但 UUID 并不是唯一的。发生 128 位冲突的可能性极小。对于 6(小于 32 位),如果您只是散列内容或生成随机字符串,很可能会发生冲突。
如果需要唯一性约束,则需要
- 随机生成一个 6 字符的字符串
- 通过查询数据库检查您之前是否生成了该字符串
- 如果你之前生成过,回到1
另一种方法是使用大小为 32 位的伪随机排列 (PRP)。块密码被建模为 PRP 函数,但支持 32 位块大小的并不多。有些是美国国家安全局的 Speck 和 Hasty Pudding Cipher。
例如,使用 PRP,您可以获取一个已经唯一的值,例如您的数据库主密钥,并使用块密码对其进行加密。如果输入不大于 32 位,则输出仍然是唯一的。
然后您将 运行 Base62(或至少 Base 41)输出并删除填充字符以获得 6 个字符的输出。
您的字母数字字符集中有 36 个字符(0-9 位数字 + a-z 字母)。有 6 个位置,您可以获得 366 = 2.176.782.336 个不同的选项,这比 231 稍大。
因此您可以使用 Unix time 创建一个唯一的 ID。但是,您必须保证没有ID在同一秒内生成。
如果您不能保证这一点,您最终会在 class 中得到一个(同步的)计数器。另外,如果你想在 JVM 重启后仍然存在,你应该保存当前值(例如,保存到数据库、文件等。无论你有什么选择)。
假设您的语料库是字母数字字母的集合。 a-zA-Z0-9
.
char[] corpus = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
我们可以使用 SecureRandom
生成一个种子,它会根据 os 向 OS 询问熵。这里的技巧是保持均匀分布,每个字节有 255 个值,但我们只需要大约 62 个,所以我将支持ose 拒绝采样。
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 的语料库,并 假设 分布是完全随机的。在这种情况下,我们有 birthday problem。这给了我们 N = 62^6 pos 兄弟姐妹。我们想找到 n 其中重复的机会在 10% 左右。
p(r)= 1 - N!/(N^n (N-n)!)
并使用维基百科页面中给出的近似值。
n = sqrt(-ln(0.9)2N)
这为我们提供了 10% 几率的大约 109000 个数字。对于 0.1% 的机会,它需要大约 10000 个数字。
我需要生成一个由 6 个字母数字字符组成的预订代码,该代码在 java 中是随机且唯一的。
尝试使用UUID.randomuuid().toString()
,但是id太长,要求只能是6个字符。
有哪些方法可以实现这一点?
澄清一下,(因为这个问题被标记为重复)。 我发现的其他解决方案只是简单地生成随机字符,这在这种情况下是不够的。我需要合理保证不再生成乱码
您可以尝试从生成的 UUID 中创建子字符串。
String uuid = UUID.randomUUID().toString();
System.out.println("uuid = " + uuid.substring(0,5);
如果你做一个子字符串,该值可能不是唯一的
有关更多信息,请参阅以下类似内容 link Generating 8-character only UUIDs
考虑使用 hashids
库生成整数的加盐哈希值(您的数据库 ID 或其他可能更好的随机整数)。
Hashids hashids = new Hashids("this is my salt",6);
String id = hashids.encode(1, 2, 3);
long[] numbers = hashids.decode(id);
尽管名称如此,但 UUID 并不是唯一的。发生 128 位冲突的可能性极小。对于 6(小于 32 位),如果您只是散列内容或生成随机字符串,很可能会发生冲突。
如果需要唯一性约束,则需要
- 随机生成一个 6 字符的字符串
- 通过查询数据库检查您之前是否生成了该字符串
- 如果你之前生成过,回到1
另一种方法是使用大小为 32 位的伪随机排列 (PRP)。块密码被建模为 PRP 函数,但支持 32 位块大小的并不多。有些是美国国家安全局的 Speck 和 Hasty Pudding Cipher。
例如,使用 PRP,您可以获取一个已经唯一的值,例如您的数据库主密钥,并使用块密码对其进行加密。如果输入不大于 32 位,则输出仍然是唯一的。
然后您将 运行 Base62(或至少 Base 41)输出并删除填充字符以获得 6 个字符的输出。
您的字母数字字符集中有 36 个字符(0-9 位数字 + a-z 字母)。有 6 个位置,您可以获得 366 = 2.176.782.336 个不同的选项,这比 231 稍大。
因此您可以使用 Unix time 创建一个唯一的 ID。但是,您必须保证没有ID在同一秒内生成。
如果您不能保证这一点,您最终会在 class 中得到一个(同步的)计数器。另外,如果你想在 JVM 重启后仍然存在,你应该保存当前值(例如,保存到数据库、文件等。无论你有什么选择)。
假设您的语料库是字母数字字母的集合。 a-zA-Z0-9
.
char[] corpus = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
我们可以使用 SecureRandom
生成一个种子,它会根据 os 向 OS 询问熵。这里的技巧是保持均匀分布,每个字节有 255 个值,但我们只需要大约 62 个,所以我将支持ose 拒绝采样。
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 的语料库,并 假设 分布是完全随机的。在这种情况下,我们有 birthday problem。这给了我们 N = 62^6 pos 兄弟姐妹。我们想找到 n 其中重复的机会在 10% 左右。
p(r)= 1 - N!/(N^n (N-n)!)
并使用维基百科页面中给出的近似值。
n = sqrt(-ln(0.9)2N)
这为我们提供了 10% 几率的大约 109000 个数字。对于 0.1% 的机会,它需要大约 10000 个数字。