Python-'ascii'コーデックはバイトをデコードできません


119

私は本当に混乱しています。エンコードしようとしましたが、エラーが表示されましたcan't decode...

>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

文字列に "u"プレフィックスを付けてエラーを回避する方法を知っています。エンコードが呼び出されたときにエラーが「デコードできない」のはなぜですか。Pythonは内部で何をしていますか?

回答:


167
"你好".encode('utf-8')

encodeUnicodeオブジェクトをオブジェクトに変換しstringます。しかし、ここではそれをstringオブジェクトで呼び出しています(uがないため)。したがって、Pythonは最初にをオブジェクトに変換するstring必要がありunicodeます。だからそれは同等のことをします

"你好".decode().encode('utf-8')

しかし、文字列が有効なASCIIではないため、デコードは失敗します。そのため、デコードできないという苦情が出ます。


50
それで、解決策は何ですか?特に、文字列リテラルがない場合は、文字列オブジェクトしかありません。
Jon Tirsen 2013年

2
@JonTirsen、文字列オブジェクトをエンコードしないでください。文字列オブジェクトは既にエンコードされています。エンコーディングを変更する必要がある場合は、Unicode文字列にデコードしてから、目的のエンコーディングとしてエンコードする必要があります。
Winston Ewert 2013年

20
だから、あなたができる上からはっきりとそれを状態に"你好".decode('utf-8').encode('utf-8')
deinonychusaur

5
@WinstonEwert私は混乱していたと思います。エンコーディング業界は、私を永遠に混乱させがちです。私の混乱は、入力が文字列なのかUnicode文字列なのか、そしてそれがどのようなエンコーディングを持っているのかを知らないという私自身の問題に起因すると思います。
deinonychusaur 2013

@deinonychusaur、ええ...私はそれを取得します。
Winston Ewert 2013

53

常にユニコードからバイトにエンコードします。
この方向では、エンコーディングを選択できます

>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好

もう1つの方法は、バイトからユニコードにデコードすることです。
この方向では、エンコーディングが何であるかを知る必要があります。

>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好

この点は十分に強調することはできません。ユニコード「モグラたたき」の再生を避けたい場合は、データレベルで何が起こっているのかを理解することが重要です。ここでは別の方法で説明されています:

  • Unicodeオブジェクトは既にデコードされているため、呼び出したくない decode
  • バイト文字列オブジェクトは既にエンコードされているため、呼び出したくないencode

ここで.encode、バイト文字列を確認すると、Python 2は最初にそれを暗黙的にテキスト(unicodeオブジェクト)に変換しようとします。同様.decodeに、Unicode文字列を確認すると、Python 2は暗黙的にそれをバイト(strオブジェクト)に変換しようとします。

これらの暗黙の変換が、を呼び出したときに取得できる理由です。これは、エンコーディングが通常、タイプのパラメータを受け入れるためです。パラメータを受け取ると、別のエンコーディングで再エンコードする前に、タイプのオブジェクトに暗黙的にデコードされます。この変換では、デフォルトの「ascii」デコーダーが選択され、エンコーダー内でデコードエラーが発生します。UnicodeDecodeErrorencodeunicodestrunicode

実際、Python 3ではメソッドstr.decodebytes.encodeも、存在しません。彼らの連れ去りは、この一般的な混乱を避けるための[物議を醸す]試みでした。

...またはコーディングに関するsys.getdefaultencoding()言及。通常これは「アスキー」です


では、Pythonはエンコードする前にバイト文字列をデコードするということですか?
thoslin 2012年

@thoslin正確に、詳細を追加しました。
2014年

_とは何ですか?また、印刷ステートメントに括弧がないのはなぜですか?
NoBugs 2017

1
@NoBugs 1. REPLでは_、前の値2.を参照します。これはpython-2.xの質問だからです。
2017

40

あなたはこれを試すことができます

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

または

以下を試すこともできます

.pyファイルの先頭に次の行を追加します。

# -*- coding: utf-8 -*- 

8

Python <3を使用している場合、文字列リテラルがUnicodeであることをuインタープリターに接頭辞として付ける必要があります。

Python 2.7.2 (default, Jan 14 2012, 23:14:09) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

さらに読むUnicode HOWTO


4
文字列をエンコードしている場合、なぜデコードエラーがスローされるのですか?
MxLDevs 2012年

3

u"你好".encode('utf8')Unicode文字列のエンコードに使用します。しかし、を表現したい"你好"場合は、デコードする必要があります。と同じように:

"你好".decode("utf8")

あなたはあなたが望むものを手に入れます。多分あなたはエンコードとデコードについてもっと学ぶべきです。


3

Unicodeを扱う場合はencode('utf-8')、の代わりに、特殊文字を無視することもできます。たとえば、

"你好".encode('ascii','ignore')

またはsomething.decode('unicode_escape').encode('ascii','ignore')ここで提案さているように

この例では特に有用ではありませんが、一部の特殊文字を変換できない場合、他のシナリオでより効果的に機能します。

または、を使用して特定の文字を置き換えるreplace()ことを検討できます。


1

Linuxまたは類似のシステム(BSD、Macについては不明)のシェルからpythonインタープリターを開始する場合は、シェルのデフォルトのエンコードも確認する必要があります。

locale charmapシェル(Pythonインタープリターではない)から呼び出すと、

[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

これが当てはまらず、他に何かが見られる場合、例えば

[user@host dir] $ locale charmap
ANSI_X3.4-1968
[user@host dir] $ 

Pythonは(少なくとも、私の場合のように)シェルのエンコーディングを継承し、(一部?すべて?)ユニコード文字を出力できません。Pythonの独自のデフォルトのエンコーディングあなたが見ていることと対照を経由sys.getdefaultencoding()し、sys.setdefaultencoding()、この場合には無視されます。

この問題があることがわかった場合は、次の方法で修正できます。

[user@host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

(または、en_ENの代わりに必要なキーマップを選択します。)/etc/locale.confこれを修正するために編集(またはシステムのロケール定義を管理するファイル)することもできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.