web-dev-qa-db-fra.com

Convertir une valeur int en unicode

J'utilise pyserial et j'ai besoin d'envoyer des valeurs inférieures à 255. Si j'envoie l'int lui-même, la valeur ascii de l'int est envoyée. Alors maintenant, je convertis l'int en une valeur unicode et je l'envoie via le port série.

unichr(numlessthan255);

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

Quelle est la meilleure façon de convertir un int en unicode?

20
user2578666

Utilisez simplement chr(somenumber) pour obtenir une valeur de 1 octet d'un int tant qu'il est inférieur à 256. pySerial l'enverra ensuite correctement.

Si vous cherchez à envoyer des choses sur pySerial, c'est une très bonne idée de regarder le module struct dans la bibliothèque standard, il gère les problèmes endiens et les problèmes d'emballage ainsi que l'encodage pour à peu près tous les types de données qui vous aurez probablement besoin d'un octet ou plus.

15
Steve Barnes

In Python 2 - Transformez-le d'abord en chaîne, puis en unicode.

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

La meilleure façon, je pense. Fonctionne avec n'importe quel entier, et fonctionne toujours si vous mettez une chaîne en entrée.

Modification mise à jour en raison d'un commentaire: Pour Python 2 et 3 - Cela fonctionne sur les deux mais un peu en désordre:

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

Je pense que la meilleure solution est d'être explicite et de dire que vous voulez représenter un nombre comme un octet (et pas comme un caractère ):

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

Cela fait fonctionner votre code à la fois en Python 2 et Python 3 (en Python 3, le résultat est, comme il se doit, un objet octets ). Une alternative, en Python 3, serait d'utiliser la nouvelle bytes([128]) pour créer un seul octet de valeur 128.

Je ne suis pas un grand fan des solutions chr(): en Python , elles produisent une chaîne (caractère, pas d'octet) qui doit être encodé avant de l'envoyer n'importe où (fichier, socket, terminal,…) —chr() en Python 3 est équivalent à la problématique Python 2 unichr() de la question. La solution struct a l'avantage de produire correctement un octet quelle que soit la version de Python. Si vous souhaitez envoyer des données sur le port série avec chr(), vous devez contrôler l'encodage qui doit avoir lieu ultérieurement. Le code peut fonctionner lorsque l'encodage par défaut utilisé par Python 3 est UTF-8 (ce qui, je pense, est le cas), mais cela est dû au fait que les caractères Unicode de point de code inférieur à 256 peuvent être codés comme un seul octet en UTF -8. Cela ajoute une couche inutile de subtilité et de complexité que je ne recommande pas (cela rend le code plus difficile à comprendre et, si nécessaire, à déboguer).

Donc, je vous suggère fortement d'utiliser l'approche ci-dessus (qui a également été suggérée par Steve Barnes et Martijn Pieters): cela indique clairement que vous voulez produire un octet (et non les caractères). Cela ne vous surprendra pas même si vous exécutez votre code avec Python 3, et cela rend votre intention plus claire et plus évidente.

10
Eric O Lebigot

Utilisez plutôt la fonction chr() ; vous envoyez une valeur inférieure à 256 mais supérieure à 128, mais créez un caractère Unicode.

Le caractère unicode doit ensuite être encodé en premier pour obtenir un caractère octet , et cet encodage échoue car vous utilisez une valeur en dehors de ASCII range (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)

Ceci est normal Python 2 comportement; lorsque vous essayez de convertir une chaîne unicode en une chaîne d'octets, un codage implicite doit avoir lieu et le codage par défaut est ASCII.

Si vous deviez utiliser chr() à la place, vous créez une chaîne d'octets d'un caractère et cet encodage implicite ne doit pas avoir lieu :

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

Une autre méthode que vous voudrez peut-être étudier est le module struct , surtout si vous devez envoyer des valeurs entières plus grandes à 255:

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

L'exemple ci-dessus regroupe un entier dans un court-circuit non signé dans l'ordre des octets réseau, par exemple.

10
Martijn Pieters