web-dev-qa-db-ja.com

文字列をCP-1251からUTF-8に変換する方法は?

Mutagenを使用して、ID3タグデータを CP-1251 / CP-1252 からUTF-8に変換しています。 Linuxでは問題ありません。しかし、Windowsでは、wx.TextCtrlで SetValue() を呼び出すとエラーが発生します。

UnicodeDecodeError: 'ascii'コーデックは位置0のバイト0xc3をデコードできません:序数が範囲(128)にありません

mutagen からプルしている元の文字列(CP-1251でエンコードされていると想定)は次のとおりです。

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

これをUTF-8に変換してみました:

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

...さらに、デフォルトのエンコーディングをASCIIからUTF-8に変更します。

sys.setdefaultencoding('utf-8')

...しかし、同じエラーが発生します。

23
jsnjack

入力にcp1251があることが確実にわかっている場合は、

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

あなたの文字列dはUnicode文字列ですnot UTF-8でエンコードされた文字列!したがって、それをdecode()することはできません。UTF-8または必要なエンコーディングにencode()する必要があります。

>>> 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'

(たとえば、UTF-8エンコードされたファイルとして保存する必要がある場合は、すべての処理の最後に行います)。

入力が別のエンコーディングである場合、それは逆になります:

>>> 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

dが正しいUnicode文字列の場合、d.encode('utf-8')はエンコードされたUTF-8バイト文字列を生成します。ただし、印刷してテストしないでください。コードページの悪意があるため、正しく表示されない場合があります。

4
Cat Plus Plus

АлександрСтепаненко回答にコメントを追加したいのですが、私の評判ではまだ許可されていません。 MP3タグをCP-1251からUTF-8に変換するという同様の問題があり、encode/decode/encodeのソリューションがうまくいきました。例外として、最初のエンコーディングを「latin-1」に置き換える必要がありました。これは、本質的にUnicode文字列を実際のエンコーディングなしのバイトシーケンスに変換します。

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

また、たとえばmutagenを使用して保存する場合は、エンコードする必要はありません。

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

私は正しい答えを見つけるために一日の半分を失いました。したがって、外部ソースwindows-1251から(私の状況ではWebサイトから)エンコードされたUnicode文字列を取得した場合、Linuxコンソールには次のように表示されます。

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

これはデータの正しいユニコード表示ではありません。それで、ティム・ピエツカーは正しいです。あなたはそれを最初にencode()し、次にdecode()し、それから正しいエンコーディングにもう一度エンコードするべきです。

したがって、私の場合、この奇妙な行は「テキスト」変数に保存され、次の行が追加されました。

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

私にくれた:

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

はい、私も夢中になります。しかし、うまくいきます!

追伸ファイルへの保存も同じ方法で行う必要があります。

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

この応答でテキストのエンコード/デコードに関するいくつかの関連情報を提供しました: https://stackoverflow.com/a/34662963/2957811

これをここに追加するには、「エンコードされた」と「デコードされた」の2つの状態のいずれかでテキストを考えることが重要です。

「デコードされた」とは、文字操作(検索、大文字小文字変換、部分文字列のスライス、文字カウントなど)または表示(フォントのコードポイントの検索)に使用できるインタープリタ/ライブラリによる内部表現であることを意味しますとグリフを描画します)が、実行中のプロセスに渡すことはできません。

「エンコードされた」とは、他のデータと同様に渡すことができるバイトストリームであることを意味しますが、操作や表示には役立ちません。

以前にシリアル化されたオブジェクトを使用したことがある場合は、「デコード」をメモリ内の有用なオブジェクトと見なし、「エンコード」をシリアル化バージョンと見なしてください。

_'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'_は、おそらくcp1251でエンコードされた、エンコード(またはシリアル化)バージョンです。これは文字をシリアル化するために使用される「言語」であり、メモリ内で文字を再作成するために必要であるため、このエンコーディングは正しい必要があります。

君は 必要 これを現在のエンコーディング(cp1251)からpythonユニコード文字にデコードし、次にutf8バイトストリームとして再エンコードします。d.decode('cp1251').encode('utf8')を提案した回答者にはこの権利があり、それがうまくいく理由を説明する手助けをしたいと思っています。

0
user2957811