2013-07-13 4 views
12

Я использую pyserial и мне нужно послать некоторые значения менее 255. Если я отправляю сам int, значение ascii для int отправляется. Итак, теперь я конвертирую int в значение unicode и отправляю его через последовательный порт.Преобразование значения 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?

+0

python2 или Python3? (угадывая Python2, но это имеет большое значение). Вы уверены, что 'unichr' - это сбой вызова? Как вы выполняете фактическую отправку возвращаемых данных unichr? –

+2

'unichr()' не существует в Python 3, поэтому это Python 2. 'unichr()' назван 'chr()' в Python 3 (преобразование в символ Unicode). – EOL

ответ

9

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

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

+0

, который работает благодаря большому количеству – user2578666

+0

@ user2578666: Если ответ вам полезен, и вы отмечаете его как принятое, справедливо также проголосовать за него. Добро пожаловать в StackOverflow! – EOL

+1

Нет репутации еще.Пожалуйста, заработайте его :-) – user2578666

8

Вместо этого используйте chr() function; вы отправляете значение меньше 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' 

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

+0

Я предполагаю, что вы имели в виду «байты», а не «символ байта»? «байтовый символ» не является общим выражением и почти является [oxymoron] (http://stackoverflow.com/questions/4545661/unicodedecodeerror-when-redirecting-to-file/4546129#4546129). Кроме того, кодировка по умолчанию не обязательно должна быть ASCII: она официально 'sys.getdefaultencoding()'. – EOL

+0

@EOL: Это Python 2, это строковый объект, который действительно представляет собой последовательность байтов. Но зацикливание на нее дает вам строки длиной 1; байтовые символы. –

+0

@EOL: кодировка по умолчанию ** является ** ASCII на Python 2, когда дело доходит до неявных кодировок (объединение строк и юникода, сравнение для равенства и т. Д.). –

6

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

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

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

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

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

+1

Bravo @EOL - один из (возможно, многих) , вводящие в заблуждение вещи о C, которые унаследованы на C++, - это отсутствие какого-либо различия между строкой, длина которой равна 1, одному символу - как текстовому, так и локальному кодированию - и байту. –

24

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

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

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

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

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

'str (integer) .encode (" utf-8 "). Decode (" utf-8 ")', в то время как уродливый, будет работать на Python 2 и 3, тогда как выше будет работать только на Python 2. –

Смежные вопросы