2013-07-13 11 views
12

Sto usando pyserial e ho bisogno di inviare alcuni valori inferiori a 255. Se invio lo stesso int, viene inviato il valore ascii dell'int. Quindi ora sto convertendo l'int in un valore unicode e inviandolo attraverso la porta seriale.Converti un valore int in unicode

unichr(numlessthan255); 

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

cosa è il modo migliore per convertire un int in Unicode?

+0

python2 o python3? (indovinando Python2, ma fa la differenza) Sei sicuro che 'unichr' è la chiamata in crash? Come stai facendo l'effettivo invio dei dati restituiti da unichr? –

+2

'unichr()' non esiste in Python 3, quindi questo è Python 2. 'unichr()' è chiamato 'chr()' in Python 3 (conversione in un carattere Unicode). – EOL

risposta

9

Basta usare chr(somenumber) per ottenere un valore di 1 byte di un int fintanto che è inferiore a 256. pySerial lo invierà correttamente.

Se siete alla ricerca di inviare le cose pySerial si tratta di un molto buona idea di guardare il modulo struct nella libreria standard gestisce endian emette un problemi di imballaggio, nonché la codifica per quasi ogni tipo di dati che si probabilmente avranno bisogno di 1 o più byte.

+0

che funziona grazie mille – user2578666

+0

@ user2578666: Se una risposta ti è utile e la contrassegni come accettata, è giusto anche votare in alto. Benvenuto in StackOverflow! – EOL

+1

Ancora nessun rappresentante. Devo guadagnare :-) – user2578666

8

Utilizzare invece chr() function; stai inviando un valore inferiore a 256 ma superiore a 128, ma stai creando un carattere Unicode.

carattere Unicode è per poi essere codificati prima di ottenere un byte carattere , e che la codifica fallisce perché si sta utilizzando un valore al di fuori della gamma 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) 

Questo è normale comportamento di Python 2; quando si tenta di convertire una stringa unicode in una stringa di byte, deve essere eseguita una codifica implicita e la codifica predefinita è ASCII.

Se si sceglie di usare chr(), invece, si crea una stringa di byte di un carattere e che codifica implicita fa non devono avere luogo:

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

Un altro metodo si potrebbe voler esaminare è la struct module, specialmente se è necessario inviare valori interi maggiore di 255:

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

Il precedente esempio confezioni un numero intero per esempio, in un byte byte di rete corto senza segno.

+0

Immagino tu intenda "byte", non "un carattere di byte"? "carattere byte" non è un'espressione comune ed è quasi un [ossimoro] (http://stackoverflow.com/questions/4545661/unicodedecodeerror-when-redirecting-to-file/4546129#4546129). Inoltre, la codifica predefinita non deve essere ASCII: è ufficialmente 'sys.getdefaultencoding()'. – EOL

+0

@EOL: Questo è Python 2, questo è un oggetto stringa, che è in realtà una sequenza di byte. Ma passandoci sopra ti dà delle stringhe di lunghezza 1; caratteri byte. –

+0

@EOL: la codifica predefinita ** è ** ASCII su Python 2, quando si tratta di codifiche implicite (concatenazione di stringhe e unicode, confronto per uguaglianza, ecc.). –

6

Penso che la soluzione migliore è quella di essere espliciti e dire che si vuole rappresentare un numero come un byte (e not as a character):

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

Questo rende il vostro lavoro il codice sia in Python 2 e Python 3 (in Python 3, il risultato è, come dovrebbe, un oggetto bytes). Un'alternativa, in Python 3, sarebbe quella di utilizzare il nuovo bytes([128]) per creare un singolo byte di valore 128.

Io non sono un grande fan dei chr() soluzioni: in Python 3, producono un (carattere, non byte) stringa che deve essere encoded prima di inviarlo ovunque (file, socket, terminale, ...) - chr() in Python 3 equivale al problema Python 2 unichr() della domanda. La soluzione struct ha il vantaggio di produrre correttamente un byte qualunque sia la versione di Python. Se si desidera inviare dati tramite la porta seriale con chr(), è necessario avere il controllo sulla codifica che deve essere eseguita successivamente.Il codice potrebbe funzionare quando la codifica predefinita utilizzata da Python 3 è UTF-8 (che penso sia il caso), ma ciò è dovuto al fatto che i caratteri Unicode del punto di codice inferiore a 256 possono essere codificati come un singolo byte in UTF -8. Questo aggiunge un inutile livello di sottigliezza e complessità che non raccomando (rende il codice più difficile da capire e, se necessario, il debug).

Quindi, suggerisco vivamente di utilizzare l'approccio di cui sopra (che è stato accennato anche da Steve Barnes e Martijn Pieters): lo rende chiaro che si vuole produrre un byte (e non caratteri). Non ti sorprenderà nemmeno se esegui il tuo codice con Python 3, e rende il tuo intento più chiaro e più ovvio.

+1

Bravo @EOL - uno dei (forse molti) , cose fuorvianti su C che C++ ha ereditato è la mancanza di qualsiasi distinzione tra una stringa che abbia una lunghezza di 1, un singolo carattere - sia il testo n la codifica locale - sia un byte. –

24

In Python 2 - Trasforma prima in una stringa, quindi in unicode.

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

Il miglior modo di pensare. Funziona con qualsiasi numero intero, inoltre funziona ancora se inserisci una stringa come input.

Aggiornato modifica a causa di un commento: Per Python 2 e 3 - Questo funziona su entrambi, ma un po 'confuso:

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

'str (integer) .encode (" utf-8 "). Decode (" utf-8 ")', mentre brutto, funzionerà su Python 2 e 3, mentre quanto sopra funzionerà solo su Python 2. –