场景: 只能用6位数, 要表示0~百亿区间的数. etc. xabdex => 2000000000.

理解进制

二进制, 逢2进1. 101 => 1x2^2 + 0x2^1 + 1x2^0 = 5 二进制3为才能表示10进制的1位数.
16进制, 逢16进1. 101 => 1x16^2 + 0x16^1 + 1x16^0 = 257 16进制101表示到了257.

64进制, 逢64进1. 101 => 1x64^2 + 0x64^1 + 1x64^0 = 4160 64进制三位表示到了4位数, 就是我们想要的.

实现(php)

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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
class UIDUtils
{

/**
* 用户唯一表示长度
*/
const CODE_LENGTH = 6;


/**
* if number is negative prefix with zero
*
*/
private static $negative = 0;

/**
* this character presentation zero
*/
private static $zeroCharacter = [ 'J', 'q', 's', 'T', 'U', 'E'];

/**
* code dictionary
*/
private static $dictionary = [
0 => 'K',
1 => 'v',
2 => 'F',
3 => 'm',
4 => 'u',
5 => 'B',
6 => 'S',
7 => 'n',
8 => 'Y',
9 => 'e',
10 => 'O',
11 => 'd',
12 => 'A',
13 => 'j',
14 => 'x',
15 => 'y',
16 => 'V',
17 => 'X',
18 => 'b',
19 => 'W',
20 => 'Q',
21 => 'P',
22 => 'z',
23 => 't',
24 => 'r',
25 => 'Z',
26 => 'R',
27 => 'w',
28 => 'c',
29 => 'p',
30 => 'I',
31 => 'G',
32 => 'k',
33 => 'C',
34 => 'h',
35 => 'f',
36 => 'l',
37 => 'i',
38 => 'o',
39 => 'N',
40 => 'L',
41 => 'M',
42 => 'D',
43 => 'a',
44 => 'g',
45 => 'H',
];

/**
* encrypt function get code
*
* @param $number
* @return string
* @throws \Error
*/
public static function encode($number)
{
$encodeString = '';
$numberType = $number < 0 ? true : false;

$dictionaryLength = count(self::$dictionary);

while($number > $dictionaryLength)
{
$encodeString = self::$dictionary[abs($number % $dictionaryLength)] . $encodeString;
$number = floor($number / $dictionaryLength);
}
if($number > 0)
$encodeString = self::$dictionary[$number] . $encodeString;

$encodeStringLength = strlen($encodeString);
$padStringLength = self::CODE_LENGTH - $encodeStringLength;


// if number is negative number and encode length is six. number overflow
if(($numberType && $padStringLength < 1) || (!$numberType && $padStringLength < 0))
throw new \Error("加密数字溢出....");

// if number is positive and encode length is six. just return it.
if($padStringLength == 0)
return $encodeString;

// if number is positive and encode length small than six. pad random character left.
shuffle(self::$zeroCharacter);

if($numberType)
$resultEncodeString = self::$negative . implode(array_slice(self::$zeroCharacter, 0, $padStringLength + 1)) . $encodeString;
else
$resultEncodeString = implode(array_slice(self::$zeroCharacter, 0, $padStringLength)) . $encodeString;

return $resultEncodeString;
}

/**
* decode string to number value
*
* @param $string
* @return int
* @throws \Error
*/
public static function decode($string)
{
$numberValue = 0;
$dictionaryLength = count(self::$dictionary);
$decodeArr = array_reverse(str_split($string));

if(count($decodeArr) != self::CODE_LENGTH)
throw new \Error("字符长度错误.");

$dictionaryNumberMap = array_flip(self::$dictionary);
foreach($decodeArr as $key => $value)
{
if(in_array($value, self::$zeroCharacter))
continue;
$numberValue += $dictionaryNumberMap[$value] * pow($dictionaryLength, $key);
}
return $numberValue;
}

$number = 10000000;

$string = UIDUtils::encode($number);
var_dump($string);

$number = UIDUtils::decode($string);
var_dump($number);

思路很重要, 实现很简单.