Python 将数字ID转换为简短、不同字母数字代码的算法

Python 将数字ID转换为简短、不同字母数字代码的算法,python,database,encryption,hash,primary-key,Python,Database,Encryption,Hash,Primary Key,我有一个数据库中的ID,我希望它们很短并且很容易用眼睛区分(即,两个相近的数字看起来不同) 像这样: 13892359163211->ALO2WE7 13992351216421->52NBEK3 或者类似的算法。有点像散列,只是需要可逆?像AES这样的加密算法几乎是理想的,只是它的输出太长了。(和过度杀戮) 我使用的是Python(3),尽管我认为这并不重要,因为“接近”的数字看起来不同 您可以使用RSA加密(然后解密)您的数字。这绝对是矫枉过正-但是。。。以下是一个例子: 安装https:/

我有一个数据库中的ID,我希望它们很短并且很容易用眼睛区分(即,两个相近的数字看起来不同)

像这样:

13892359163211->ALO2WE7
13992351216421->52NBEK3

或者类似的算法。有点像散列,只是需要可逆?像AES这样的加密算法几乎是理想的,只是它的输出太长了。(和过度杀戮)


我使用的是Python(3),尽管我认为这并不重要,因为“接近”的数字看起来不同

您可以使用RSA加密(然后解密)您的数字。这绝对是矫枉过正-但是。。。以下是一个例子: 安装
https://github.com/sybrenstuvel/python-rsa
pip安装rsa

导入rsa
导入rsa.core
#(pubkey,privkey)=rsa.新密钥(64)#生成密钥对
PublicKey=rsa.PublicKey(n=9645943279888986023,e=65537)
PrivateKey=rsa.PrivateKey(n=9645943279888986023,e=65537,d=7507666207464026273,p=9255782423,q=1042153201)
打印(“1”,rsa.core.encrypt_int(13892359163211,pubkey.e,pubkey.n))
打印(“第二”,rsa.core.encrypt_int(13992351216421,pubkey.e,pubkey.n))
打印(“1st”,十六进制(rsa.core.encrypt_int(13892359163211,pubkey.e,pubkey.n))[2:]
打印(“第二”,十六进制(rsa.core.encrypt_int(13992351216421,pubkey.e,pubkey.n))[2:]
#如果你想比较两个相似的数字
对于范围内的i(13892359163211、13892359163251):
encrypted=rsa.core.encrypt\u int(i,pubkey.e,pubkey.n)
#decrypted=rsa.core.decrypt_int(加密,privkey.d,privkey.n)
打印(i,十六进制(加密)[2:],加密)
请注意,您不能加密大于
pubkey.n
的数字。这是一个与RSA相关的限制。通过使用更高的
n
生成不同的密钥对,可以避免此问题。如果希望所有生成的数字具有相同的长度,请在其前面加上前导零。你也可以考虑让它们大写以便更好的可读性。为了使显示的字符串更短,请考虑下面的旧答案中提到的Base62编码。 输出

1st 5427392181794576250
2nd 7543432434424555966
1st 4b51f86f0c99177a
2nd 68afa7d5110929be

input          hex(encrypted)   encrypted
13892359163211 4b51f86f0c99177a 5427392181794576250
13892359163212 2039f9a3f5cf5d46 2322161565485194566
13892359163213 173997b57918a6c3 1673535542221383363
13892359163214 36644663653bbb4  244958435527080884
13892359163215 c2eeec0c054e633  877901489011746355
...
旧答案与显示的数字略短有关,没有意识到它们看起来应该有很大的不同

您希望将数字的基数从10改为更大的数字,以便使用更少的字符。请参阅底座62的示例(
a-zA-Z0-9

或者对于基数为16的快速脏数据(
0-9A-F
,十六进制)

hex(13892359163211)[2:]#->“ca291220d4b”

如何查找输入的
crc32
,并以十六进制显示结果

>>> n = 13892359163211
>>> 
>>> import binascii
>>> hex(binascii.crc32(str(n).encode()))[2:]
'240a831a'

将数字ID转换为二进制形式(3),并使用编码器(4,5)


使用哪种编码器取决于您希望允许使用哪些字符。

问题的陈述比解决更容易。一种解决方案是借用保留格式的加密的一些思想,但由于安全性不是目标,因此可以简化。使用Feistel密码框架,可以编写一个非常简短且可逆的“混合”函数,然后编写一个简短的编码函数,以实现您想要的东西

导入hashlib
导入字符串
掩码=(1>22,id_in&掩码
L^=func(R)
R^=func(L)
返回(L>22,混合和遮罩
R^=func(L)
L^=func(R)
return(L您可以使用idea将整数转换为base64。这将是最短的

  • 13892359163211是
    4LWL
  • 13992351216421是
    64yl

这个问题是,两个类似的十进制数在HeHAI中看起来也一样。用RSA更新。请考虑更新你的问题,使这一要求更加突出。<代码>短而容易区分的眼睛< /代码>并不能完全传达完整的信息。对我来说不一样。@JamesKPolk完全一样。我的错误。CRC32只对值可逆。为什么向下投票?“这个问题没有显示任何研究成果;它不清楚或没有用处”。非常清楚和有用,我已经研究过了(参见:AES和哈希)要使它们显著缩短,需要在右侧有一个比a-Z0-9更大的字母表。Sidenote,这不是我问题的答案,而是另一种方法:您可以简单地生成随机字符串并将其附加到数据库中的行/文档中。这很好,但您仍然需要使用一种不会导致错误的随机技术产生重复项。这也不能解决问题!!!长度需要固定,不同的ID需要有本质上的不同!长度是固定的,因为转换为8字节的二进制。想到的唯一能为相近的数字产生“本质上不同”结果的算法是哈希函数。。。
In [1]: import struct, base64

In [2]: i = 13892359163211
Out[2]: 13892359163211

In [3]: struct.pack('L', i)
Out[3]: b'K\r"\x91\xa2\x0c\x00\x00'

In [4]: base64.b85encode(struct.pack('L', i)).decode('ascii')
Out[4]: 'OAR8Cq6`24'

In [5]: base64.b64encode(struct.pack('L', i)).decode('ascii')[:-1]
Out[5]: 'Sw0ikaIMAAA'
13892359163211 -> BC33VXN8A
13992351216421 -> D1UOW6SLL
BC33VXN8A -> 13892359163211
D1UOW6SLL -> 13992351216421