用户不重复邀请码生成

摘要:
  产生短长度的随机不重复唯一邀请码方式.搜集于网络,如侵权请留言删除

UUID 变种,产生 8 位字符串

短8位UUID思想其实借鉴微博短域名的生成方式,但是其重复概率过高,而且每次生成4个,需要随即选取一个,本算法利用62个可打印字符,通过随机生成32位UUID,由于UUID都为十六进制,所以将UUID分成8组,每4个为一组,然后通过模62操作,结果作为索引取出字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z" };

public static String generateShortUuid() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString();

}

base 编码方式实现,产生 6 位邀请码的数据格式

6位邀请码:0-9十个数字,26个大写字母,在这其中再去除掉0和1,O和I防止它们两两混淆。总共获得了32个可用字符。那么能生成的邀请码总数为32的6次方,也就是1073741824个。10亿+个邀请码,在业务初期足够用户使用,如果随着业务的发展可对位数进行扩充。一般情况用户ID或用户编号都为长整型数且递增,那么现在我们将用户ID映射成一个6位的base32编码.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

import java.util.Random;

/\*\*

- 邀请码生成器,基本原理:<br/>
- 1)入参用户 ID:1 <br/>
- 2)使用自定义进制转换之后为:V <br/>
- 3)转换未字符串,并在后面添加'A':VA <br/>
- 4)在 VA 后面再随机补足 4 位,得到:VAHKHE <br/>
- 5)反向转换时以'A'为分界线,'A'后面的不再解析 <br/>
- \*/
public class ShareCodeUtils {

/**
* 自定义进制(0,1没有加入,容易与o,l混淆),数组顺序可进行调整增加反推难度,A用来补位因此此数组不包含A,共31个字符。
*/
private static final char[] BASE = new char[]{'H', 'V', 'E', '8', 'S', '2', 'D', 'Z', 'X', '9', 'C', '7', 'P',
'5', 'I', 'K', '3', 'M', 'J', 'U', 'F', 'R', '4', 'W', 'Y', 'L', 'T', 'N', '6', 'B', 'G', 'Q'};

/**
* A补位字符,不能与自定义重复
*/
private static final char SUFFIX_CHAR = 'A';

/**
* 进制长度
*/
private static final int BIN_LEN = BASE.length;

/**
* 生成邀请码最小长度
*/
private static final int CODE_LEN = 6;

/**
* ID转换为邀请码
*
* @param id
* @return
*/
public static String idToCode(Long id) {
char[] buf = new char[BIN_LEN];
int charPos = BIN_LEN;

// 当id除以数组长度结果大于0,则进行取模操作,并以取模的值作为数组的坐标获得对应的字符
while (id / BIN_LEN > 0) {
int index = (int) (id % BIN_LEN);
buf[--charPos] = BASE[index];
id /= BIN_LEN;
}

buf[--charPos] = BASE[(int) (id % BIN_LEN)];
// 将字符数组转化为字符串
String result = new String(buf, charPos, BIN_LEN - charPos);

// 长度不足指定长度则随机补全
int len = result.length();
if (len < CODE_LEN) {
StringBuilder sb = new StringBuilder();
sb.append(SUFFIX_CHAR);
Random random = new Random();
// 去除SUFFIX_CHAR本身占位之后需要补齐的位数
for (int i = 0; i < CODE_LEN - len - 1; i++) {
sb.append(BASE[random.nextInt(BIN_LEN)]);
}

result += sb.toString();
}

return result;
}

/**
* 邀请码解析出ID<br/>
* 基本操作思路恰好与idToCode反向操作。
*
* @param code
* @return
*/
public static Long codeToId(String code) {
char[] charArray = code.toCharArray();
long result = 0L;
for (int i = 0; i < charArray.length; i++) {
int index = 0;
for (int j = 0; j < BIN_LEN; j++) {
if (charArray[i] == BASE[j]) {
index = j;
break;
}
}

if (charArray[i] == SUFFIX_CHAR) {
break;
}

if (i > 0) {
result = result * BIN_LEN + index;
} else {
result = index;
}
}

return result;

}

public static void main(String[] args) {
String code = idToCode(1L);
System.out.println(code);
System.out.println(codeToId(code));
}

}