Подтвердить что ты не робот

Преобразование значения int в unicode

Я использую pyserial и мне нужно послать некоторые значения меньше 255. Если я отправляю сам int, значение ascii для int отправляется. Итак, теперь я конвертирую int в значение unicode и отправляю его через последовательный порт.

unichr(numlessthan255);

However it throws this error:
'ascii' codec can't encode character u'\x9a' in position 24: ordinal not in range(128)

Каков наилучший способ преобразования int в unicode?

4b9b3361

Ответ 1

Просто используйте chr(somenumber), чтобы получить 1 байтовое значение int, если оно меньше 256. pySerial затем отправит его в порядке.

Если вы смотрите на отправку вещей по pySerial, очень хорошая идея взглянуть на структурный модуль в стандартной библиотеке, он обрабатывает проблемы с endian, а также кодирует практически все типы данных, которые, вероятно, будут требуется 1 байт или более.

Ответ 2

В Python 2 - сначала переведите его в строку, затем в юникод.

str(integer).decode("utf-8")

Лучший способ, я думаю. Работает с любым целым числом, плюс все еще работает, если вы вставляете строку в качестве ввода.

Обновлено редактирование из-за комментария: для Python 2 и 3 - это работает на обоих, но немного беспорядочно:

str(integer).encode("utf-8").decode("utf-8") 

Ответ 3

Используйте chr() функцию; вы отправляете значение меньше 256, но более 128, но создаете символ Юникода.

Затем символ Юникода должен быть сначала закодирован, чтобы получить байтовый символ, и эта кодировка завершилась неудачно, потому что вы используете значение вне диапазона ASCII (0-127):

>>> str(unichr(169))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa9' in position 0: ordinal not in range(128)

Это нормальное поведение Python 2; при попытке преобразовать строку юникода в строку байта, неявное кодирование должно иметь место, а кодировка по умолчанию - ASCII.

Если бы вы использовали chr() вместо этого, вы создаете байтовую строку одного символа и что неявное кодирование не должно иметь места:

>>> str(chr(169))
'\xa9'

Другим способом, который вы можете захотеть изучить, является struct module, особенно если вам нужно отправить целочисленные значения больше 255:

>>> struct.pack('!H', 1000)
'\x03\xe8'

В приведенном выше примере пакет, например, упаковывает целое число в байты без знака в сетевом порядке.

Ответ 4

Я думаю, что лучшее решение должно быть явным и говорить, что вы хотите представить число в виде байта (и не как символ):

>>> import struct
>>> struct.pack('B', 128)
>>> '\x80'

Это заставляет ваш код работать как на Python 2, так и на Python 3 (в Python 3 результат, как и должно быть, bytes объект). Альтернативой в Python 3 было бы использовать новый bytes([128]) для создания одного байта значения 128.

Я не являюсь большим поклонником решений chr(): в Python 3, они создают строку (символ, а не байт) который должен быть закодирован перед отправкой в ​​любом месте (файл, сокет, терминал,...) - chr() в Python 3 эквивалентен проблемному Python 2 unichr() вопрос. Преимущество решения struct заключается в правильном создании байта независимо от версии Python. Если вы хотите отправить данные через последовательный порт с помощью chr(), вам необходимо будет контролировать кодировку, которая должна иметь место впоследствии. Код может работать, если кодировка по умолчанию, используемая Python 3, - это UTF-8 (что, на мой взгляд, так и есть), но это связано с тем, что символы Unicode с кодовой точкой меньше 256 могут быть закодированы как один байт в UTF -8. Это добавляет ненужный слой тонкости и сложности, которые я не рекомендую (это делает код более сложным для понимания и, при необходимости, отладки).

Итак, я настоятельно рекомендую вам использовать вышеприведенный подход (на что также намекнул Стив Барнс и Martijn Pieters): он дает понять, что вы хотите создать байт (а не символы). Это не даст вам сюрпризов, даже если вы запустите свой код с Python 3, и это сделает ваше намерение более ясным и более очевидным.