Python UUID представлен в виде специальных символов - PullRequest
1 голос
/ 17 февраля 2010

При создании UUID в Python, likeo:

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

Как можно отобразить этот UUID в строку, состоящую из заглавного алфавита AZ, без символов D, F, I, O, Q и U, плюс числовые цифры, а также символы "+" и "=" , то есть из целого числа или строки в набор из 32 (относительно дружественных OCR) символов:

[ABCEGHJKLMNPRSTVWXYZ1234567890+=]

Я назову этот набор OCRf (для распознавания текста).

Я бы хотел иметь изоморфную функцию:

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

Однако я хотел бы знать, является ли этот метод лучшим и быстрым способом преобразования, или же существует более простой и быстрый метод (например, встроенный, более умный алгоритм или просто лучший метод).

Я благодарен за ваш вклад. Спасибо.

Ответы [ 3 ]

2 голосов
/ 17 февраля 2010

Насколько важно для вас «сжать» представление на 18,75%, то есть с 32 до 26 символов? Потому что, если сохранение этого небольшого процента байтов не является абсолютно необходимым, что-то вроде uid.hex.upper().replace('D','Z') будет делать то, что вы просите (не используя весь алфавит, который вы делаете доступным, но единственная стоимость этого отсутствует - 18,75% «сжатия») .

Если сжатие каждого последнего байта имеет решающее значение, я бы поработал с подстроками по 20 бит каждая - это 5 шестнадцатеричных символов, 4 символа в вашем классном алфавите. Есть 6 из них (плюс 8 оставшихся битов, за которые вы можете взять hex.upper().replace, как указано выше, так как нечего выигрывать, делая что-то более изощренное). Вы можете легко получить подстроки, нарезав .hex и превратив каждую в int с int(theslice, 16). Затем вы можете в основном применить тот же алгоритм, который вы использовали выше - но арифметика все делается на гораздо меньших числах, поэтому выигрыш в скорости должен быть существенным. Кроме того, не создавайте строку, зацикливаясь на += - составьте список всех «цифр» и ''.join их всех в конце - это также улучшение производительности.

1 голос
/ 17 февраля 2010
transtbl = string.maketrans(
  'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
  'ABCEGHJKLMNPRSTVWXYZ1234567890+='
)

uuidstr = uuid.uuid1()

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

Да, этот метод действительно делает меня немного больным, спасибо за вопрос.

1 голос
/ 17 февраля 2010
>>> 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'
...