UnicodeEncodeError, le plus grand ennemi naturel (exagération) des programmeurs Python (avec Python2) qui gèrent le japonais. La personne à côté de moi hier était la proie, et pendant que j'aidais à le résoudre, j'ai pu régler un peu le sens du traitement des chaînes dans Python 2. (Je veux bientôt mettre sur pied une version de Python 3)
La chaîne d'octets est codée par une méthode de codage spécifique (ex. Utf-8), et est exprimée par `` ça '' dans le littéral. D'un autre côté, une chaîne de caractères Unicode est un arrangement de points de code Unicode, et dans le littéral, ʻu est ajouté comme ʻu'that'
.
python
(py2.7)~ » ipython
(réduction)
>>> 'Ah' #Chaîne d'octets
Out[1]: '\xe3\x81\x82'
>>> u'Ah' #Chaîne Unicode
Out[2]: u'\u3042'
>>> 'Ah'.decode('utf-8') (or unicode('Ah', 'utf-8')) #Chaîne d'octets->Chaîne Unicode(=Décoder)
Out[3]: u'\u3042'
>>> u'Ah'.encode('utf-8') #Chaîne Unicode->Chaîne d'octets(=Encoder)
Out[4]: '\xe3\x81\x82'
Si vous vérifiez avec la fonction type
, vous pouvez voir que la chaîne d'octets est de type str
/ la chaîne unicode est de type ʻunicode`.
python
>>> type('a')
Out[5]: str
>>> type(u'a')
Out[6]: unicode
De plus, dans Python2, les chaînes d'octets et les chaînes Unicode sont des chaînes et peuvent être concaténées.
python
>>> u'a' + 'a'
Out[7]: u'aa'
Oui, je dois gérer le japonais (pour être exact, tous les caractères non ASCII)! Comme vous pouvez le voir dans la sortie de l'exemple ci-dessus, la combinaison d'une chaîne Unicode et d'une chaîne d'octets produit une chaîne Unicode. Dans le processus, vous devez décoder la chaîne d'octets en une chaîne Unicode, mais le problème ici est que la chaîne Python n'a aucune information sur son propre codage.
«Si vous ne savez pas comment encoder, vous pouvez le décoder en ASCII», dit Python, et Hello UnicodeEncodeError. Il est rare que les littéraux fassent de telles erreurs, mais il est facile de faire des erreurs si vous ne faites pas attention aux chaînes de caractères reçues de l'extérieur de votre propre programme (y compris les entrées / sorties standard).
python
>>> u'a' + 'Ah' #Chaîne Unicode et chaîne d'octets(Non-ASCII)Combiner
---------------------------------------------------------------------------
UnicodeDecodeError Traceback (most recent call last)
<ipython-input-8-084e015bd795> in <module>()
----> 1 u'a' + 'Ah'
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)
>>> u'a' + 'Ah'.decode('utf-8') #Chaîne d'octets->Chaîne Unicode
Out[9]: u'a\u3042'
>>> print(u'a' + 'Ah'.decode('utf-8'))
a ah
La raison du passage à une chaîne Unicode au lieu d'une chaîne d'octets est qu'il est souvent plus pratique de travailler avec une chaîne au niveau du point de code qu'au niveau des octets. Par exemple, si vous voulez compter le nombre de caractères, vous pouvez utiliser la fonction len
pour les chaînes Unicode. D'autre part, une chaîne d'octets renvoie le nombre d'octets, elle ne peut donc pas être utilisée avec cette intention.
python
>>> len(u'Ah')
Out[11]: 3
>>> len('Ah')
Out[12]: 9
N'est pas. À titre d'exemple, considérons le programme simple suivant.
test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print(u'Ah' + u'Dire')
Essayez de l'exécuter dans le terminal. La majorité des gens peuvent probablement le faire sans problème.
python
(py2.7)~ » python test.py
Ah
Alors qu'en est-il de la redirection des résultats de l'exécution vers un fichier? Il existe de nombreux environnements dans lesquels UnicodeEncodeError se produit, comme illustré ci-dessous.
python
(py2.7)~ » python test.py > test.txt
Traceback (most recent call last):
File "test.py", line 4, in <module>
print(u'Ah')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
Dans l'exemple print (u'Ai ')
, une chaîne de caractères Unicode est passée à la sortie standard, mais à ce stade, la chaîne de caractères Unicode-> octet est convertie (encodée).
Si l'entrée / sortie standard est connectée au terminal, Python sélectionnera automatiquement la méthode de codage appropriée à partir de la valeur de locale (ex. Variable d'environnement LANG). D'autre part, lorsque l'entrée / sortie standard est connectée à un autre que le terminal par redirection, etc., les informations pour sélectionner une méthode de codage appropriée ne peuvent pas être obtenues, et le codage est tenté en ASCII, et dans la plupart des cas (= lorsque des caractères non-ASCII sont inclus). Échouer.
(ref.) http://blog.livedoor.jp/dankogai/archives/51816624.html
Le codage de la chaîne Unicode avant de la transmettre à la sortie standard peut résoudre ce problème.
test.py(Chaîne Unicode->Chaîne d'octets)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print((u'Ah' + u'Dire').encode('utf-8'))
En spécifiant la variable d'environnement PYTHONIOENCODING
, la méthode de codage utilisée peut être fixée indépendamment de la locale. Si vous spécifiez cela, vous n'avez pas à l'encoder un par un.
python
(py2.7)~ » cat test.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print(u'Ah' + u'Dire')
(py2.7)~ » PYTHONIOENCODING=utf-8 python test.py > test.txt
(py2.7)~ » cat test.txt
Ah
(ref.) http://methane.hatenablog.jp/entry/20120806/1344269400