Python 将UUID 32个字符的十六进制字符串转换为;YouTube风格“;短id和背面

Python 将UUID 32个字符的十六进制字符串转换为;YouTube风格“;短id和背面,python,guid,uuid,Python,Guid,Uuid,我正在使用uuid.uuid1()为所有MongoDB文档分配一个GUID。我想要一种方法,可以派生出一个11个字符、唯一的、区分大小写的YouTube-like ID,比如 1_XmY09uRJ4 从uuid生成的十六进制字符串 ae0a0c98-f1e5-11e1-9t2b-1231381dac60 我希望能够动态地将缩短的ID与十六进制匹配,反之亦然,而不必在数据库中存储另一个字符串。有没有人有一些示例代码,或者可以为我指出可以实现这一点的模块或公式的方向?您可以查看Python的b

我正在使用uuid.uuid1()为所有MongoDB文档分配一个GUID。我想要一种方法,可以派生出一个11个字符、唯一的、区分大小写的YouTube-like ID,比如

1_XmY09uRJ4 
从uuid生成的十六进制字符串

ae0a0c98-f1e5-11e1-9t2b-1231381dac60

我希望能够动态地将缩短的ID与十六进制匹配,反之亦然,而不必在数据库中存储另一个字符串。有没有人有一些示例代码,或者可以为我指出可以实现这一点的模块或公式的方向?

您可以查看Python的
base64
模型。GUID本质上是一个数字的base-16表示形式,您可以删除连字符,从base-16解码,然后编码到base-64。相反,需要从base64开始解码,在base16中编码,并在适当的位置插入连字符。

将基础字节转换为base64值,去掉
=
填充和换行符

您可能希望使用,以避免使用
/
+
-
),因此生成的字符串可以用作URL路径元素:

>>> import uuid, base64
>>> base64.urlsafe_b64encode(uuid.uuid1().bytes).rstrip(b'=').decode('ascii')
'81CMD_bOEeGbPwAjMtYnhg'
反之:

>>> uuid.UUID(bytes=base64.urlsafe_b64decode('81CMD_bOEeGbPwAjMtYnhg' + '=='))
UUID('f3508c0f-f6ce-11e1-9b3f-002332d62786')
要将其转换为通用函数,请执行以下操作:

from base64 import urlsafe_b64decode, urlsafe_b64encode
from uuid import UUID

def uuid2slug(uuidstring):
    return urlsafe_b64encode(UUID(uuidstring).bytes).rstrip(b'=').decode('ascii')

def slug2uuid(slug):
    return str(UUID(bytes=urlsafe_b64decode(slug + '==')))
这为您提供了一种以更紧凑的形式表示16字节UUID的方法。进一步压缩会丢失信息,这意味着您无法再次将其解压缩到完整的UUID。16个字节可以表示的完整值范围将永远不适合少于22个base64字符的任何内容,这需要每3个字节输入4个字符,每个字符编码6位信息


因此,YouTube的唯一字符串不是基于完整的16字节UUID,它们的11个字符的ID可能存储在数据库中以便于查找,并且基于较小的值。

对于那些专门寻找以url安全方式缩短UUID的方法的人,可以简化来自的真正有用的答案,一些人使用模块来处理url不安全的字符,类似于来自该答案的注释(没有一些不必要的位)


什么是“t”?我不知道你指的是什么to@yourfriendzak:您的UUID包含一个“t”,使其无效。这很奇怪…我直接从UUID.hex输出复制并粘贴了它…AFAIR,UUID有一个时间组件。您的字符串可能使用“t”作为分隔符。@UUID永远不会显示为带有时间组件的十六进制。
t
中断第9个字节(16个字节中的第9个字节)的十六进制表示;它通常是一个十六进制数字。我的钱在
f
上,OP将其误读为
t
,或者他们在某个点按了
t
键并选择了该数字。无论如何,Python的
uuid.uuid1()
只会生成一个
uuid.uuid()
实例,它的hex属性输出值的8-4-4-4-12十六进制数字表示,并且永远不会包含
t
。这里,
t
是时钟序列值的14位的一部分(当从右向左计数时,位9-12)。
import base64
import uuid

# uuid to b64 string and back
uuid_to_b64str = base64.urlsafe_b64encode(uuid.uuid1().bytes).decode('utf8').rstrip('=\n')
b64str_to_uuid = uuid.UUID(bytes=base64.urlsafe_b64decode(f'{uuid_to_b64str}=='))

# uuid string to b64 string and back
uuidstr_to_b64str = base64.urlsafe_b64encode(uuid.UUID(str(uuid.uuid1())).bytes).decode('utf8').rstrip('=\n')
b64str_to_uuidstr = str(uuid.UUID(bytes=base64.urlsafe_b64decode(f'{uuidstr_to_b64str}==')))