如何生成固定长度唯一随机字符串?

2018-01-15 17:41:45 +08:00
 xfund4
1. 字符串长度固定在 8 位[a-zA-Z0-9],仅要求千万数据量下保证唯一
2. 不需要根据随机串解码出原值。
3. 随机串不能被猜测出。
4. 有自增 ID 可以使用,但是随机串不能有规律。
13706 次点击
所在节点    PHP
57 条回复
yingfengi
2018-01-15 21:05:34 +08:00
非程序员,写过一些小东西,我记得 php 有个获取当前时间戳生成一个 ID 的函数还是啥,生成的这个 ID 会是毫秒级的,反正是这么一个东西,之前用过,生成 ID 后 md5 作为一个 key,当初是这样只玩的。
你可以,md5 之后随机取 8 位啥的
以上,仅供参考
billlee
2018-01-15 21:52:46 +08:00
block_ciper(counter())
fuyufjh
2018-01-15 21:56:46 +08:00
最科学的方法:把输出看成一个(26+26+10)进制、8 位的数

random.randint(0, (26+26+10)**8)
nccer
2018-01-15 22:41:01 +08:00
生成个池子,用的时候在里面选一个.
zhx1991
2018-01-16 00:13:40 +08:00
用上面说的某种碰撞很低但不是没有的随机策略

然后在库里把这个字段设成唯一

插入重复数据会报错(非常罕见), 捕获相应异常重来
janxin
2018-01-16 11:05:06 +08:00
提前生成随机字母数字池,过滤清洗重复数据。这段时间不占用业务响应时间。使用的时候取出任意(从头部或尾部取出),销毁之。
w3sy
2018-01-16 11:28:56 +08:00
@Magnus1k 完全正确,数学问题,不用讨论了
janxin
2018-01-16 11:32:26 +08:00
刚刚说的还是比较业务偷懒了,其实技术一点的方法是设计一个映射算法即可。随便想了一个简单的:保证安全性前提下可以使用带校验位方式,可以占一个字母;为了混淆,可随机生成 2 位随机位,也可以用于后续 ID 的运算随机位可重复没关系,占用两个字节,不要求安全就随机三个字节;自增 ID 占用 5 位即可满足现有数量级需求,可按位或其他方式进行运算得到一个,还可以带入之前取到的随机数进行,凯撒之类的简单算法就可以。顺序还可以随机排序组合,能识别的前提下 XD
raptor
2018-01-16 11:53:40 +08:00
千万级就是小于 1 亿,对应二进制不到 27 位。
A-Z1-9 8 位,相当于 35 进制的 8 位,对应二进制 41 位多点。
生成一个 14 位的随机数,左移 27 位,和 ID 组成一个 41 位二进制数。
自己设置一个密钥,再用 RC4 加密这个 41 位二进制数。
最后把这个加密后的二进制数转为 35 进制的 A-Z1-9。

这样可以保证唯一,猜不到,不用查数据库三个要求。

解出 ID 的方法:
字符串转成二进制,RC4 解密,把 41 位二进制最高 14 位填充成 0,再补 23 位 0 填充成 64 位,转成整数即是 ID。
mingl0280
2018-01-16 12:23:36 +08:00
SHA1/MD5 一个随机值(真随机值)取其中随意八位,然后查库有没有碰撞到的……
其实讲道理这个碰撞在千万量级应该是不可能的……
chuhemiao
2018-01-16 13:10:45 +08:00
是时候上区块链思想了
lbp0200
2018-01-16 15:10:28 +08:00
从老外那,抄来的
od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
pheyx
2018-01-16 16:16:10 +08:00
@honeycomb 你这个想法确实挺笨又 low 的
mengzhuo
2018-01-16 17:10:27 +08:00
总空间只有 = 218,340,105,584,896
你的要求是 = 000,000,0xx,xxx,xxx

正好对半开
把时间填在前面,唯一 id 填到后面,然后随便位移,置换,异或一下就好了(反正没人会真的看你的算法)
SooHoo
2018-01-16 17:54:33 +08:00
这两天公司业务需求,提现码(不能重复,不能被猜测到,不能太长,最多 6 位)
大概说下生成规则

先将数字小写字母大写字母打乱
然后左边取 20 个字符作为 randomKey
剩下右边给 numKey

将用户 id 进行 numKey.length 进制换算,生成字符串 result

长度不足 6 个,从 randomKey 随机取 6 个字符,插入 result 字符串 随机位置
SooHoo
2018-01-16 17:57:40 +08:00
@SooHoo

接上 ,没发完 不小心发出来了
----------
大概思想就是把 uid 放入到串里面,然后,随机插入 不包括 uid 的字符

为了让用户稍微难些分析。就加入了进制转换,然后随机插入位置。

可能有 BUG,欢迎指正。哈哈

-----------------------------------------



/**
*
* @param count 字符个数
* @param uid 用户 id
* @return
*/
public static String randomString(int count, int uid) {

String randomKey = CODE.substring(0, 20);
String numKey = CODE.substring(20);

StringBuilder result = new StringBuilder();

while (uid > 0) { //转成 numKey.length 进制
int p = uid % numKey.length();
result.append(numKey.substring(p, p + 1));
uid = uid / numKey.length();
}

if (result.length() < count) {//字数不足,随机字符补全
Random random = new Random();
int size = count - result.length();
for (int i = 0; i < size; i++) {
int r = random.nextInt(randomKey.length()); //随机取一个字符
int p = random.nextInt(result.length() + 1);//随机一个位置
result.insert(p, randomKey.substring(r, r + 1));
}
}
return result.toString();
}
wwhc
2018-01-17 05:00:43 +08:00
md6sum -d32 用户 ID/随机数

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/423093

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX