java - 如何在 java 中生成 5 个字符的唯一字母数字值?
问题描述
我为一个银行项目工作,他们的要求是为每笔交易生成唯一的交易参考。UTR 的格式为:
<BankCode><YYDDD><5 位 SequenceId>。
这个 5 位数的序列 ID 也可以是字母数字。每天的交易数量可以达到 100-200K。
如果我使用 Oracle 序列,那么我只能有 10K 个值。
我尝试使用SecureRandom
生成器并生成 200K 5 长度的字符串,但它生成了大约 30 个重复的字符串。
下面是我使用的代码片段
int leftLimit = 48;
int rightLimit = 122;
int i1=0;
Random random = new SecureRandom();
while (i1<200000) {
String generatedString = random.ints(leftLimit, rightLimit+1)
.filter(i -> (i<=57||i>=65) && ( i<=90|| i>=97))
.limit(5)
.collect(StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append)
.toString();
System.out.println(generatedString);
i1++;
}
解决方案
如果你想要一个伪随机序列,我建议你使用自定义的Feistel实现。Feistel 被设计为一种互惠机制,因此您可以通过重新应用它来解码 Feistel,这意味着i == feistel(feistel(i))
如果您从 1 到 X,您将获得 1 和 X 之间的所有数字恰好一次。所以没有碰撞。
基本上,您可以使用 36 个字符。因此,您有 60,466,176 个可能的值,但您只需要其中的 200,000 个。但实际上,我们不在乎你想要多少,因为 Feistel 确保没有碰撞。
您会注意到二进制中的 60,466,176 是0b11100110101010010000000000
,这是一个 26 位的数字。26 对代码不是很友好,所以我们将自定义 feistel 映射器包装成 24 位。Feistel 必须将一个数字分成两个偶数部分,每个部分都是 12 位。这只是为了解释您将在下面的代码中看到的值,如果您查看其他实现,它是 12 而不是 16。此外,0xFFF
是 12 位的掩码。
现在算法本身:
static int feistel24bits(int value) {
int l1 = (value >> 12) & 0xFFF;
int r1 = value & 0xFFF;
for (int i = 0; i < 3; i++) {
int key = (int)((((1366 * r1 + 150889) % 714025) / 714025d) * 0xFFF);
int l2 = r1;
int r2 = l1 ^ key;
l1 = l2;
r1 = r2;
}
return (r1 << 12) | l1;
}
所以基本上,这意味着如果你给这个算法一个介于0
和16777215
( = 2 24 -1) 之间的数字,你将得到一个唯一的伪随机数,当用 base-36 编写时,它可以容纳在 5 个字符串中。
那么如何让这一切正常工作呢?嗯,这很简单:
String nextId() {
int sequence = (retrieveSequence() + 1) & 0xFFFFFF; // bound to 24 bits
int nextId = feistel24bits(sequence);
storeSequence(sequence);
return intIdToString(nextId);
}
static String intIdToString(int id) {
String str = Integer.toString(id, 36);
while(str.length() < 5) { str = "0" + str; }
return str;
}
推荐阅读
- bash - 'gawk' 不是内部或外部命令、可运行程序或批处理文件。但类似路径中的其他文件可以在 Cmd 中运行
- php - 选择选项中的附加属性
- reactjs - 反应 useEffect 警告以放置缺少的依赖项。但是钩子中的依赖值发生了变化
- r - 复制聚类观察并为复制的聚类创建唯一标识符
- python - 我正在尝试根据日期列标题过滤数据框,例如“数据 b/w 7 月 1 日至 7 月 5 日”,但我无法在 py 中检索切片
- python - 使用Python将.csv文件读入数组时如何解决错误
- angular - 如何从angular8中的鼠标事件函数访问变量?
- azure - ARM 模板 - 设置对现有 RBAC 角色的依赖
- angular - 错误 0:nativescript 中的未知错误 http 失败响应
- javascript - TypeError Joi.validate 不是函数