我有两张桌子:category(cat_id type int,cat_name)
和books(book_id type int,cat_id)
。当我将一本书分配给用户时,他将获得一个book code
. 我想形成包含 12 个字母数字字符的本书代码,它必须源自cat_id
and book_id
。此外,我应该能够解码代码以获得cat_id
and book_id
。任何想法?。
3 回答
使用 HEX 有一种更简单的方法,但您需要决定书籍使用多少位数以及类别使用多少位数。
例如,我建议将 8 用于书籍,将 4 用于类似的类别。通过使用十六进制一,最大记录为 FFFFFFFF FFFF,您可以在其中用完所有无符号整数的书籍(最多 4294967295 本书)和 65535 个类别。
实际上,LPAD(HEX(book_id), 8, '0')
对于前 8 位数字和LPAD(HEX(cat_id), 4, '0')
后 4 位数字。
所以你想要的书代码可以通过SELECT CONCAT(LPAD(HEX(book_id), 8, '0'),LPAD(HEX(cat_id), 4, '0')) FROM books
要取回:
SELECT UNHEX(substr(code,1,8)) as book_id, UNHEX(substr(code,9,4)) as cat_id FROM bookcode WHERE id=1
如果您想在书籍代码中包含更大的数据集,您可以尝试对这两个项目使用 base36 甚至 base62(区分大小写)编码。这种编码需要您自己的用户程序代码。
好的,给你...
这可以处理最大有符号整数类型。并且产生不超过 12 个字符。
$firstId = "2147483646";
$secondId = "2147483646";
$firstBinary = str_pad(base_convert($firstId, 10, 2), 31, "0", STR_PAD_LEFT);
$secondBinary = str_pad(base_convert($secondId, 10, 2), 31, "0", STR_PAD_LEFT);
$finalBase36 = str_pad(base_convert($firstBinary.$secondBinary, 2, 36), 12, "0", STR_PAD_LEFT);
var_dump($finalBase36);
更新:对不起,我犯了一个错误..这应该用更新的代码来解决问题。
假设int
类型是 32 位无符号整数。2int
组合将有 2^64 个唯一值,大约为 1.844e19。
如果我们只使用小写或大写英文字母加数字,则有 36^12 = 4.738e18 个不同的值,这不足以创建从 2 个键到书码的一对一映射。
如果您在图书代码的字符集中再添加 5 个字符,则将有 41^12 = 2.256e19 个不同的值,这足以创建一对一映射。
但是,转换将涉及除法和乘法,当您从书本代码转换回键时,可能会发生整数溢出。
如果可能,您可能希望将字符集扩展到 64 个字符:26 * 2 小写/大写英文字母、10 个数字和 2 个特殊字符(可能是_
或-
),您可以在其中玩位移位 - 这是安全的整数溢出。对于未使用的位,您可能希望用随机数据填充它,这些数据由 2 个密钥播种;反向构造将忽略具有随机位的(固定)位置。