Python 3 - декодирование байтов, которые содержат смесь шестнадцатеричного и юникод - PullRequest
1 голос
/ 31 мая 2019

Я портирую кодовую базу для Lasersaur лазерного резца с Python2 на Python3, и у меня возникли некоторые проблемы с декодированием последовательных данных, поступающих с бортового Arduino , Данные поступают в виде потока байтов, который смешивает шестнадцатеричные и юникодные данные, например:

bytes: b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'
data:  A C 251 255 255 x 133 128 128 y 128 128 128 z

Python2 смог выполнить прокрутку данных смешанного типа и считывать последовательные данные в виде строки символов, после чего ord() использовался для определения, представляет ли символ данные или символ состояния. Вы можете увидеть, как это реализовано в исходном коде Python2, начиная с строка 367 здесь .

ord(data): 65 67 251 255 255 120 133 128 128 121 128 128 128 122

Python3 более строг в отношении кодировок и выдает мне следующую ошибку, когда я пытаюсь bytes.decode('utf-8'), потому что он получает первые шестнадцатеричные данные b'x\fb' и задыхается, потому что это другой формат. Возиться с несколькими разными кодеками не дает лучших результатов.

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 2: invalid start byte

Я обнаружил этот поток StackOverflow , который в значительной степени обращается к тому, что мне нужно, но кажется, что обработка ошибок в Python 3 больше не работает так же, и выдает мне эту ошибку, когда я пытаюсь найти решение там : TypeError: 'UnicodeDecodeError' object is not subscriptable.

Я мог бы изменить встроенный код на Arduino, чтобы получить более последовательную кодировку, но главная причина, по которой я портирую на Python3, заключается в том, что я не могу получить нужные (читай: старые) библиотеки Python2 для того, чтобы выполнить код, и я не хочу сталкиваться со сценарием, в котором я случайно попадаю в состояние, когда невозможно установить связь с бортовым arduino.

То, что я хотел бы сделать, это максимально точно имитировать исходную функциональность и получить либо строку символов, на которой я могу назвать ord(), либо сочетание символов и чисел в списке. Я немного растерялся, как это сделать.

1 Ответ

0 голосов
/ 31 мая 2019

У вас нет «смешанных» данных, у вас есть объект байтов. Когда вы печатаете его, Python представляет все байты, значение которых соответствует букве в ASCII как буква, чтобы помочь нам идентифицировать текст среди них.

Вы можете получить доступ к любому отдельному байту в виде целого числа путем индексации:

data = b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'

print(data[0])
# 65

Значение возвращается как целое число. (здесь 65, что соответствует 'A' в ASCII, отсюда его представление в байтовой строке.)

Итак, простой способ преобразовать байты в список целых чисел:

data_as_int = [b for b in data]

или даже проще:

data_as_int = list(data)

что дает нам:

print(data_as_int)
# [65, 67, 251, 255, 255, 191, 120, 133, 128, 128, 192, 121, 128, 128, 128, 192, 122]

О вашей идее преобразования байтов в строку, чтобы потом использовать ord: вы можете сделать это, но вы должны использовать кодировку, подобную latin1, в которой каждый байт соответствует одному символу - который не в случае с utf8. Итак, вы могли бы сделать что-то вроде:

data_as_int = [ord(c) for c in data.decode('latin1')]

но это менее прямое решение, чем приведенное выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...