Java根据唯一数字ID生成不重复多位邀请码的思考和实现(数字+字母)

Java根据唯一ID生成唯一邀请码


场景:

需要通过资料码,拿到数据库中的某个文件资源
需要通过邀请码,对某个用户做一些操作

这个资料码和邀请码都是随机码,多位,由数字和字母组成,可以与整形类型的ID相互转换


网络上找到的实现方法,进行一些简单思考和更改

1. 如何保证不重复性质?

我们发现进制数是不重复的,我们来看一下进制数

比如二进制, 二位二进制数可以表示 2^2个十进制数 [0,3]
比如四进制, 二位四进制数可以表示 4^2个十进制数 [0,15]
比如三十二进制,二位三十二进制数可以表示 32^2个十进制数 [0,1023]
我们得出: X位N进制数可以表示 N^X 个十进制数

不重复与唯一数字ID的联系

当唯一数字ID可以用十进制表示的时候,那么该十进制就有对应的唯一的某进制的表示,同理,某进制数有唯一的十进制表示。

假设用户在数据库中主键ID为17,我们用二进制作为邀请码来表示这个用户: 10001 ,如果我们希望邀请码是8位数的,那么可以在前面或者后面用一些不属于 二进制 的字符补位,比如 2 3 4 a b c这些不属于二进制的字符。那么就有邀请码:
J10001

我们后续在通过邀请码计算用户的主键ID时候,就可以进行: 过滤进制外的字符,提取进制数,计算出十进制ID

2. 如何引申到邀请码(自定义数字+字母)?

我们把进制引申一下

我们看到平时见到的十六进制 用a表示10 b表示11等等,都是通过一个字符来代替这个数字

那么,二进制就是 0 1表示吗?

我们可以拿其它符号表示,效果也是一样的

01
ab

那么上面这个自定义二进制表示十进制数 3 就是: ab (等同于原来的二进制11

同样的, 四进制就是 0 1 2 3 表示吗?

我们拿其他符号表示,效果也是一样的

0123
wany

那么上面这个自定义四进制表示十进制数 13 就是: ya(等同于原来的四进制 31

我们把这种引申的方法引到我们的邀请码中

假设我们的邀请码是4位的32进制数+随机字符补齐

首先我们自定义一下我们的32进制数

  /** 自定义进制(0,1没有加入,容易与o,l混淆) */
 private static final char[] r=new char[]
 {'q', 'w', 'e', '8', 'a', 's', '2', 'd',
  'z', 'x', '9', 'c', '7', 'p', '5', 'i', 
  'k', '3', 'm', 'j', 'u', 'f', 'r', '4', 
  'v', 'y', 'l', 't', 'n', '6', 'b', 'g'};

这样看,三十二进制中每一位的 0 用 q 表示, 1 用 w 表示,如此类推,31 用 g 表示。同时,我们在自定义的时候尽量不要加入 0 和1 ,容易与 o, l 混淆

接下来我们来自定义一下用来补齐的随机字符

我们用 o作为分隔符,前面是随机数字,后面是唯一进制数

比如 7ojp 邀请码中, 7o是随机补齐字符,过滤掉,剩下的 jp就是我们的自定义32进制数,我们查表知道: j表示19,p表示13,那么计算出来的ID就是

ID = 13 * 32^0+ 19 * 32^1 = 13 + 608 = 621 

我们换算得出用户ID是621。

同样的,根据这个ID,利用我们的自定义32进制和随机字符补齐,就可以得出一个这个ID一对一的邀请码

首先我们明确一点,之前提到的 邀请码中的 7o是被这个ID一对一唯一生成过程中产生的随机补齐字符,所以接下来我们就假设生成的 补齐字符是 7o 如果在这里有误解,请理清产生过程和先来后到

根据ID 621,我们得出进制数表示 jp

在不足4位,我们补足4位,生成随机补齐字符 7o 放在进制数前面

生成邀请码 7ojp

如果已足四位则不用补齐,如果是三位,前面只补 o,如果三位以下,前面补 对应个数随机数字 + o

我们生成的邀请码的一些性质
1. 最大可表示的 ID

X位N进制可以表示 max = N^X 的十进制ID
比如 4位32进制可以表示 max = 1_048_576 的十进制ID (一百万)

2. 其他

好像没啥其他…


贴上网传代码(注意:没有处理溢出)

public class CodeUtil {

    /** 自定义进制(0,1没有加入,容易与o,l混淆) */
    private static final char[] r=new char[]{'q', 'w', 'e', '8', 'a', 's', '2', 'd', 'z', 'x', '9', 'c', '7', 'p', '5', 'i', 'k', '3', 'm', 'j', 'u', 'f', 'r', '4', 'v', 'y', 'l', 't', 'n', '6', 'b', 'g', 'h'};

    /** (不能与自定义进制有重复) */
    private static final char b='o';

    /** 进制长度 */
    private static final int binLen=r.length;

    /** 序列长度 */
    private static final int s=4;

    /**
     * 根据ID生成六位随机码
     * @param id ID
     * @return 随机码
     */
    public static String toSerialCode(long id) {
        char[] buf=new char[32];
        int charPos=32;

        while((id / binLen) > 0) {
            int ind=(int)(id % binLen);
            // System.out.println(num + "-->" + ind);
            buf[--charPos]=r[ind];
            id /= binLen;
        }
        buf[--charPos]=r[(int)(id % binLen)];
        // System.out.println(num + "-->" + num % binLen);
        String str=new String(buf, charPos, (32 - charPos));
        // 不够长度的自动随机补全
        if(str.length() < s) {
            StringBuilder sb=new StringBuilder();
            sb.append(b);
            Random rnd=new Random();
            for(int i=1; i < s - str.length(); i++) {
            sb.append(r[rnd.nextInt(binLen)]);
            }
            str+=sb.toString();
        }
        return str;
    }

    public static long codeToId(String code) {
        char chs[]=code.toCharArray();
        long res=0L;
        for(int i=0; i < chs.length; i++) {
            int ind=0;
            for(int j=0; j < binLen; j++) {
                if(chs[i] == r[j]) {
                    ind=j;
                    break;
                }
            }
            if(chs[i] == b) {
                break;
            }
            if(i > 0) {
                res=res * binLen + ind;
            } else {
                res=ind;
            }
            // System.out.println(ind + "-->" + res);
        }
        return res;
    }
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值