web-dev-qa-db-fra.com

Comment convertir une chaîne de CP-1251 en UTF-8?

J'utilise mutagen pour convertir les données de balises ID3 de CP-1251 / CP-1252 en UTF-8. Sous Linux, il n'y a pas de problème. Mais sous Windows, appeler SetValue() sur un wx.TextCtrl produit l'erreur:

UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet 0xc3 en position 0: l'ordinal n'est pas dans la plage (128)

La chaîne d'origine (supposée être codée CP-1251) que je tire de mutagen est:

u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'

J'ai essayé de convertir cela en UTF-8:

dd = d.decode('utf-8')

... et même changer l'encodage par défaut de ASCII en UTF-8:

sys.setdefaultencoding('utf-8')

... Mais je reçois la même erreur.

23
jsnjack

Si vous savez avec certitude que vous avez cp1251 dans votre entrée, vous pouvez le faire

d.decode('cp1251').encode('utf8')
25
Johannes Charra

Votre chaîne d est une chaîne Unicode, pas une chaîne encodée en UTF-8! Donc, vous ne pouvez pas decode() it, vous devez encode() it en UTF-8 ou tout autre encodage dont vous avez besoin.

>>> d = u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> d
u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> print d
Áåëàÿ ÿáëûíÿ ãðîìó
>>> a.encode("utf-8")
'\xc3\x81\xc3\xa5\xc3\xab\xc3\xa0\xc3\xbf \xc3\xbf\xc3\xa1\xc3\xab\xc3\xbb\xc3\xad\xc3\xbf \xc3\xa3\xc3\xb0\xc3\xae\xc3\xac\xc3\xb3'

(ce que vous feriez à la fin de tout traitement lorsque vous devez l'enregistrer en tant que fichier encodé UTF-8, par exemple).

Si votre entrée est dans un encodage différent, c'est l'inverse:

>>> d = "Schoßhündchen"                 # native encoding: cp850
>>> d = "Schoßhündchen".decode("cp850") # decode from Windows codepage
>>> d                                   # into a Unicode string (now work with this!)
u'Scho\xdfh\xfcndchen'
>>> print d                             # it displays correctly if your Shell knows the glyphs
Schoßhündchen
>>> d.encode("utf-8")                   # before output, convert to UTF-8
'Scho\xc3\x9fh\xc3\xbcndchen'
5
Tim Pietzcker

Si d est une chaîne Unicode correcte, alors d.encode('utf-8') donne un bytestring UTF-8 encodé. Ne le testez pas en imprimant, cependant, il se peut qu'il ne s'affiche tout simplement pas correctement en raison des manigances des pages de codes.

4
Cat Plus Plus

Je préfère ajouter un commentaire à la réponse de Александр Степаненко mais ma réputation ne le permet pas encore. J'ai eu un problème similaire de conversion de balises MP3 du CP-1251 en UTF-8 et la solution d'encodage/décodage/encodage a fonctionné pour moi. Sauf que j'ai dû remplacer le premier encodage par "latin-1", qui convertit essentiellement la chaîne Unicode en séquence d'octets sans encodage réel:

print text.encode("latin-1").decode('cp1251').encode('utf8')

et pour sauvegarder en utilisant par exemple mutagène, il n'a pas besoin d'être encodé:

audio["title"] = title.encode("latin-1").decode('cp1251')
1
Andrey

J'ai perdu la moitié de ma journée pour trouver la bonne réponse. Donc, si vous avez obtenu une chaîne Unicode à partir de la source externe Windows 1251 encodée (à partir du site Web dans ma situation), vous verrez dans la console Linux quelque chose comme ceci:

u '\ u043a\u043e\u043c\u043d\u0430\u0442\u043d\u0430\u044f\u043a\u0432\u0430\u0440\u0442\u0438\u0440\u0430 .....' '

Il ne s'agit pas d'une présentation unicode correcte de vos données. Donc, Tim Pietzcker a raison. Vous devez d'abord l'encoder (), puis le décoder (), puis l'encoder à nouveau pour corriger l'encodage.

Donc, dans mon cas, cette étrange ligne a été enregistrée dans la variable "text" et la ligne:

print text.encode("cp1251").decode('cp1251').encode('utf8')   

m'a donné:

"Своя 2-х комнатная квартира с отличным ремонтом ...."

Oui, ça me rend fou aussi. Mais ça marche!

P.S. En enregistrant dans un fichier, vous devez procéder de la même manière.

some_file.write(text.encode("cp1251").decode('cp1251').encode('utf8'))

J'ai fourni des informations pertinentes sur l'encodage/décodage du texte dans cette réponse: https://stackoverflow.com/a/34662963/2957811

Pour ajouter à cela ici, il est important de penser au texte dans l'un des deux états possibles: "encodé" et "décodé"

'décodé' signifie qu'il est dans une représentation interne de votre interprète/bibliothèque qui peut être utilisé pour la manipulation de caractères (par exemple, recherches, conversion de casse, découpage de sous-chaînes, nombre de caractères, ...) ou l'affichage (recherche d'un point de code dans une police et dessiner le glyphe), mais ne peut pas être transmis dans ou hors du processus en cours.

"encodé" signifie qu'il s'agit d'un flux d'octets qui peut être transmis comme toutes les autres données, mais n'est pas utile pour la manipulation ou l'affichage.

Si vous avez déjà travaillé avec des objets sérialisés auparavant, considérez "décodé" comme l'objet utile en mémoire et "encodé" comme étant la version sérialisée.

'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3' Est votre version encodée (ou sérialisée), vraisemblablement encodée avec cp1251. Cet encodage doit être correct car c'est la "langue" utilisée pour sérialiser les caractères et est nécessaire pour recréer les caractères en mémoire.

Tu avoir besoin pour le décoder à partir de son encodage actuel (cp1251) en python caractères unicode, puis le réencoder comme un flux d'octets utf8. Le répondeur qui a suggéré d.decode('cp1251').encode('utf8') avait ce droit, J'espère juste aider à expliquer pourquoi cela devrait fonctionner.

0
user2957811