Преобразование значения 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?
Ответы
Ответ 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, и это сделает ваше намерение более ясным и более очевидным.