1

在 Python 中创建 UUID 时,如下所示:

>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')

怎么能将该 UUID 映射为由大写字母 AZ 减去字符 D、F、I、O、Q 和 U,再加上数字,再加上字符“+”和“=”组成的字符串。即从整数或字符串到 32 个(相对 OCR 友好)字符集:

[ABCEGHJKLMNPRSTVWXYZ1234567890+=]

我将其称为OCRf集合(对 OCR 友好)。

我想要一个同构函数:

def uuid_to_ocr_friendly_chars(uid)
    """takes uid, an integer, and transposes it into a string made 
       of the the OCRf set
    """
    ...

我的第一个想法是完成将uuid更改为base 32的过程。例如

OCRf = "ABCEGHJKLMNPRSTVWXYZ1234567890+="

def uuid_to_ocr_friendly_chars(uid):
     ocfstr = ''
     while uid > 1:
        ocfstr += OCRf[uid % 32]
        uid /= 32
     return ocfstr

但是,我想知道这种方法是否是进行这种转换的最佳和最快的方法 - 或者是否有更简单和更快的方法(例如内置、更智能的算法或更好的方法)。

我很感谢你的意见。谢谢你。

4

3 回答 3

2

将表示“压缩”18.75%(即从 32 到 26 个字符)对您来说有多重要?因为,如果保存这一小部分字节不是绝对重要的,那么类似的东西uid.hex.upper().replace('D','Z')会按照您的要求进行(不使用您提供的整个字母表,但唯一的成本是缺少 18.75% 的“挤压”)。

如果压缩每个最后一个字节至关重要,那么我将处理每个 20 位的子字符串——即 5 个十六进制字符,4 个时髦字母表中的字符。其中有 6 个(加上剩下的 8 位,你可以hex.upper().replace按照上面的方法使用,因为做任何更花哨的事情没有任何好处)。您可以通过切片轻松获取子字符串.hex并将每个字符串转换为带有int(theslice, 16). 然后,您基本上可以应用您在上面使用的相同算法 - 但算术都是在小得多的数字上完成的,因此速度增益应该是实质性的。另外,不要通过循环来构建字符串+=——列出所有“数字”,并''.join在最后列出它们——这也是一种性能改进。

于 2010-02-17T04:24:54.367 回答
1
>>> OCRf = 'ABCEGHJKLMNPRSTVWXYZ1234567890+='
>>> uuid = 'a8098c1a-f86e-11da-bd1a-00112444be1e'
>>> binstr = bin(int(uuid.replace("-",""),16))[2:].zfill(130)
>>> ocfstr = "".join(OCRf[int(binstr[i:i+5],2)] for i in range(0,130,5))
>>> ocfstr
'HLBJJB2+ETCKSP7JWACGYGMVW+'

再次转换回来

>>> "%x"%(int("".join(bin(OCRf.index(i))[2:].zfill(5) for i in ocfstr),2))
'a8098c1af86e11dabd1a00112444be1e'
于 2010-02-17T04:34:38.120 回答
1
transtbl = string.maketrans(
  'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
  'ABCEGHJKLMNPRSTVWXYZ1234567890+='
)

uuidstr = uuid.uuid1()

print base64.b32encode(str(uuidstr).replace('-', '').decode('hex')).rstrip('=').translate(transtbl)

是的,这个方法确实让我有点不舒服,谢谢你的提问。

于 2010-02-17T08:04:13.883 回答