UUID Python representado como caracteres especiais
-
21-09-2019 - |
Pergunta
Ao criar um UUID em Python, assim:
>>> uuid.uuid1()
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
Como alguém poderia mapear esse UUID em uma string composta pelo alfabeto AZ maiúsculo menos os caracteres D, F, I, O, Q e U, mais os dígitos numéricos, mais os caracteres "+" e "=".ou sejade um número inteiro ou string para o conjunto de 32 caracteres (relativamente compatíveis com OCR):
[ABCEGHJKLMNPRSTVWXYZ1234567890+=]
Vou chamar isso de OCRf
definido (para compatibilidade com OCR).
Eu gostaria de ter uma função isomórfica:
def uuid_to_ocr_friendly_chars(uid)
"""takes uid, an integer, and transposes it into a string made
of the the OCRf set
"""
...
Meu primeiro pensamento é passar pelo processo de alteração do uuid para base 32.por exemplo.
OCRf = "ABCEGHJKLMNPRSTVWXYZ1234567890+="
def uuid_to_ocr_friendly_chars(uid):
ocfstr = ''
while uid > 1:
ocfstr += OCRf[uid % 32]
uid /= 32
return ocfstr
No entanto, gostaria de saber se este método é a melhor e mais rápida maneira de fazer essa conversão - ou se existe um método mais simples e rápido (por exemplo,um algoritmo integrado, mais inteligente ou apenas um método melhor).
Estou grato pela sua contribuição.Obrigado.
Solução
Quão importante é para você “espremer” a representação em 18,75%, ou seja, de 32 para 26 caracteres?Porque, se salvar esta pequena porcentagem de bytes não for absolutamente crucial, algo como uid.hex.upper().replace('D','Z')
fará o que você pedir (não usar todo o alfabeto que você disponibiliza, mas o único custo disso é faltar aqueles 18,75% de “aperto”).
Se comprimir até o último byte for crucial, eu trabalharia em substrings de 20 bits cada - são 5 caracteres hexadecimais, 4 caracteres em seu alfabeto descolado.Existem 6 deles (mais 8 bits restantes, para os quais você pode pegar o hex.upper().replace
como acima, já que não há nada a ganhar em fazer algo mais sofisticado).Você pode obter facilmente as substrings fatiando .hex
e transforme cada um em um int com um int(theslice, 16)
.Então, você pode basicamente aplicar o mesmo algoritmo usado acima - mas a aritmética é toda feita em números muito menores, então o ganho de velocidade deve ser material.Além disso, não construa a string fazendo um loop +=
- faça uma lista de todos os "dígitos" e ''.join
todos eles no final - isso também é uma melhoria de desempenho.
Outras dicas
>>> 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+'
Para converter novamente
>>> "%x"%(int("".join(bin(OCRf.index(i))[2:].zfill(5) for i in ocfstr),2))
'a8098c1af86e11dabd1a00112444be1e'
transtbl = string.maketrans(
'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
'ABCEGHJKLMNPRSTVWXYZ1234567890+='
)
uuidstr = uuid.uuid1()
print base64.b32encode(str(uuidstr).replace('-', '').decode('hex')).rstrip('=').translate(transtbl)
Sim, este método faz me deixe um pouco doente, obrigado por perguntar.