85-битные кодированные строки не обрабатываются правильно при декодировании в python - PullRequest
0 голосов
/ 25 августа 2018

Я закодировал шестнадцатеричный код (идентификатор устройства):

9F1D8E8BA2194CD29CC744083914535A

В 85-битовое кодированное число (эквивалентное преобразование):

T,irMU)?YQSB"#\'3>>Cq

Все они хранятся в кадре данных искры.

Проблема в том, что когда я пытаюсь преобразовать его обратно (передавая столбец в UDF), он не возвращает мне идентификатор устройства, при отладке я обнаружил, что на самом деле он выводит:

T,irMU)?YQSB"#\\\'3>>Cq

Это означает, что фактическая строка автоматически добавляет escape-символ и затем декодирует его.

Это udf, я написал для преобразования:

def convert_id(id):
    id = id.replace("-", "")
    return str(bs64.a85encode(bytearray.fromhex(id)))[2:-1]

udf_convert_id = udf(convert_id, StringType())

Это для декодированияэто:

def convert_docid2idfa(docId):
    try:
        docId = docId.replace('\\\\','\\')
        id_str = bs64.a85decode(docId).hex()
        idfa = id_str[:8]+"-"+id_str[8:12]+"-"+id_str[12:16]+"-"+id_str[16:20]+"-"+id_str[20:]
        return idfa
    except:
        return docId

convert_docid2idfa_udf = udf(convert_docid2idfa, StringType())

И я расшифровываю эту версию, у которой есть выход.

1 Ответ

0 голосов
/ 25 августа 2018

Значение фактического кодированного идентификатора ASCII85 должно быть:

T,irMU)?YQSB"#'3>>Cq

В значении не должно быть \.Неправильно ваше преобразование результата a85encode() в строку:

str(bs64.a85encode(bytearray.fromhex(id)))[2:-1]

a85encode() возвращает объект bytes, вам необходимо декодировать , что, как ASCII,чтобы получить строковое значение с теми же кодовыми точками:

bs64.a85encode(bytearray.fromhex(id)).decode('ASCII')

str(bytesobject) дает удобное для отладки представление , которое безопасно вставить обратно в код Python, поэтому любой 'символы экранируются с \ впереди.Вы не хотите использовать это представление для сериализации.

Обратите внимание, что вам не нужен bytearray, обычного неизменяемого объекта bytes достаточно для декодирования шестнадцатеричного идентификатора в двоичную строку:

bs64.a85encode(bytes.fromhex(id)).decode('ASCII')

Демонстрация:

>>> import base64 as b64
>>> id = '9F1D8E8BA2194CD29CC744083914535A'
>>> encoded = bs64.a85encode(bytes.fromhex(id)).decode('ASCII')
>>> print(encoded)
T,irMU)?YQSB"#'3>>Cq
>>> b64.a85decode(encoded).hex()
'9f1d8e8ba2194cd29cc744083914535a'

Если вы не можете восстановить кодировку, вы все равно можете восстановить поврежденные значения с помощью кодека unicode_escape;сначала закодируйте строку в ASCII.Вы должны быть в состоянии обнаружить такое неработающее значение, проверив длину: 20-байтовый IDFA всегда должен приводить к 20-символьной строке ASCII85, все, что больше нуждается в исправлении:

if len(docId) > 20:
    docId = docId.encode('ascii').decode('unicode_escape')
decoded = b64.a85decode(docId).hex()

Выше исправлены ошибкивведено путем вызова str() для объекта байтов:

>>> encoded
'T,irMU)?YQSB"#\'3>>Cq'
>>> botched = str(encoded.encode('ascii'))[2:-1]
>>> botched
'T,irMU)?YQSB"#\\\'3>>Cq'
>>> botched.encode('ascii').decode('unicode_escape')
'T,irMU)?YQSB"#\'3>>Cq'
>>> bs64.a85decode(botched.encode('ascii').decode('unicode_escape')).hex()
'9f1d8e8ba2194cd29cc744083914535a'

Обратите внимание, что если вы работаете со значениями IDFA, вы можете использовать uuid.UUID() класс для преобразования между представлениями:

from uuid import UUID

bs64.a85encode(UUID(hex=id).bytes).decode('ASCII')

для кодирования и

str(UUID(bytes=bs64.a85decode(docId)))

для возврата к шестнадцатеричной строке 8-4-4-4-12 с тире:

>>> from uuid import UUID
>>> id = '9F1D8E8B-A219-4CD2-9CC7-44083914535A'
>>> encoded = bs64.a85encode(UUID(hex=id).bytes).decode('ASCII')
>>> encoded
'T,irMU)?YQSB"#\'3>>Cq'
>>> str(UUID(bytes=bs64.a85decode(encoded)))
'9f1d8e8b-a219-4cd2-9cc7-44083914535a'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...