修正方法: 「UnicodeDecodeError: 'ascii' コーデックはバイトをデコードできません」 質問する

修正方法: 「UnicodeDecodeError: 'ascii' コーデックはバイトをデコードできません」 質問する
as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
  File "/usr/local/bin/wok", line 4, in
    Engine()
  File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
    self.load_pages()
  File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
    p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
  File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
    page.meta['content'] = page.renderer.render(page.original)
  File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
    return markdown(plain, Markdown.plugins)
  File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
    return md.convert(text)
  File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
    source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

どうすれば修正できますか?

他の Python ベースの静的ブログ アプリでは、中国語の投稿を正常に公開できます。たとえば、次のアプリです。http://github.com/vrypan/bucket3私のサイトではhttp://bc3.brite.biz/、中国語の投稿は正常に公開できます。

ベストアンサー1

tl;dr / クイックフィックス

Python 2.x の Unicode Zen - ロングバージョン

原因を見なければ根本的な原因を知るのは難しいので、一般的な話をしなければなりません。

UnicodeDecodeError: 'ascii' codec can't decode bytestrこれは通常、元の文字列のエンコーディングを指定せずに、非 ASCII を含むPython 2.x を Unicode 文字列に変換しようとした場合に発生します。

簡単に言うと、Unicode 文字列は、エンコードを含まない完全に別の種類の Python 文字列です。Unicodeポイント コードのみを保持するため、スペクトル全体の任意の Unicode ポイントを保持できます。文字列には、UTF-8、UTF-16、ISO-8895-1、GBK、Big5 などのエンコードされたテキストが含まれます。文字列は Unicode にデコードされUnicode は文字列にエンコードされます。ファイルとテキスト データは常にエンコードされた文字列で転送されます。

Markdown モジュールの作成者は、おそらくunicode()(例外がスローされる場所) を残りのコードの品質ゲートとして使用します。これは、ASCII を変換するか、既存の Unicode 文字列を新しい Unicode 文字列に再ラップします。Markdown の作成者は、受信文字列のエンコードを認識できないため、Markdown に渡す前に文字列を Unicode 文字列にデコードすることをユーザーに頼ることになります。

Unicode文字列は、文字列のプレフィックスを使用してコード内で宣言できますu。例:

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

Unicode 文字列は、ファイル、データベース、ネットワーク モジュールから取得される場合もあります。この場合、エンコードについて心配する必要はありません。

落とし穴

strを明示的に呼び出さなくても、から Unicode への変換が行われることがありますunicode()

次のシナリオではUnicodeDecodeError例外が発生します。

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'         

café次の図では、端末の種類に応じて単語が「UTF-8」または「Cp1252」エンコードでどのようにエンコードされているかがわかります。どちらの例でも、cafは通常の ASCII です。UTF-8 では、 はé2 バイトを使用してエンコードされます。「Cp1252」では、é は 0xE9 です (これは偶然にも Unicode ポイント値でもあります (偶然ではありません))。正しいコードdecode()が呼び出され、Python Unicode への変換が成功します。文字列が Python Unicode 文字列に変換される図

この図では、decode()が で呼び出されますascii(これは、エンコードを指定せずに を呼び出すのと同じですunicode())。ASCII には より大きいバイトを含めることができないため0x7F、例外がスローされますUnicodeDecodeError

間違ったエンコーディングで Python Unicode 文字列に変換される文字列の図

ユニコードサンドイッチ

コード内に Unicode サンドイッチを形成するのは良い習慣です。つまり、すべての受信データを Unicode 文字列にデコードし、Unicode で作業し、最後にstrs にエンコードして出力します。これにより、コード内の文字列のエンコードについて心配する必要がなくなります。

入力/デコード

ソースコード

ソースコードに非ASCII文字を組み込む必要がある場合は、文字列の前にu. を付けてUnicode文字列を作成してください。例:

u'Zürich'

Python がソース コードをデコードできるようにするには、ファイルの実際のエンコーディングと一致するエンコーディング ヘッダーを追加する必要があります。たとえば、ファイルが 'UTF-8' としてエンコードされている場合は、次のようにします。

# encoding: utf-8

これは、ソース コードに非 ASCII が含まれている場合にのみ必要です。

ファイル

通常、ファイルから非 ASCII データが受信されます。ioモジュールは、指定されたを使用してファイルをオンザフライでデコードする TextWrapper を提供しますencoding。ファイルには正しいエンコーディングを使用する必要があります。簡単に推測することはできません。たとえば、UTF-8 ファイルの場合:

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
     my_unicode_string = my_file.read() 

my_unicode_stringは Markdown に渡すのに適しています。行UnicodeDecodeErrorに がある場合はread()、おそらく間違ったエンコーディング値を使用しています。

CSV ファイル

Python 2.7のCSVモジュールは非ASCII文字をサポートしていません。ただし、バックポート

上記のように使用しますが、開いたファイルを渡します。

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
    for row in csv.reader(my_file):
        yield row

データベース

ほとんどの Python データベース ドライバーは Unicode でデータを返すことができますが、通常は少し設定が必要です。SQL クエリには常に Unicode 文字列を使用してください。

マイグレーション

接続文字列に以下を追加します:

charset='utf8',
use_unicode=True

例えば

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL

追加:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

ウェブ

ウェブページは、ほぼあらゆるエンコードでエンコードできます。Content-typeヘッダーにはエンコードを示すフィールドを含める必要がありますcharset。その後、この値に基づいてコンテンツを手動でデコードできます。または、Pythonリクエストの Unicode を返しますresponse.text

手動で

文字列を手動でデコードする必要がある場合は、 を実行するだけです。my_string.decode(encoding)ここencodingで は適切なエンコーディングです。Python 2.x でサポートされているコーデックは次のとおりです。標準エンコーディングもう一度言いますが、 が表示される場合は、UnicodeDecodeErrorおそらくエンコードが間違っています。

サンドイッチの肉

通常の文字列と同じように Unicode を操作します。

出力

標準出力 / 印刷

printstdout ストリームを通じて書き込みます。Python は、Unicode がコンソールのエンコーディングにエンコードされるように、stdout にエンコーダーを設定しようとします。たとえば、Linux シェルの が の場合localeen_GB.UTF-8出力は にエンコードされますUTF-8。Windows では、8 ビット コード ページに制限されます。

ロケールの破損など、コンソールの設定が間違っていると、予期しない印刷エラーが発生する可能性があります。PYTHONIOENCODING環境変数によって、stdout のエンコードを強制できます。

ファイル

入力と同様に、io.openUnicode をエンコードされたバイト文字列に透過的に変換するために使用できます。

データベース

読み取り用の同じ構成により、Unicode を直接書き込むことができます。

Python3 について

Python 3 は Python 2.x よりも Unicode に対応しているわけではありませんが、このトピックに関する混乱は少し少なくなっています。たとえば、regular はstr現在 Unicode 文字列であり、oldstrは現在 ですbytes

デフォルトのエンコーディングは UTF-8 なので、.decode()エンコーディングを指定せずにバイト文字列を入力すると、Python 3 は UTF-8 エンコーディングを使用します。これにより、おそらく Unicode に関する問題の 50% が解決されます。

さらに、open()デフォルトではテキスト モードで動作するため、デコードされた値str(Unicode 値) が返されます。エンコードはロケールから取得されます。通常、Un*x システムでは UTF-8、Windows ボックスでは windows-1251 などの 8 ビット コード ページになります。

使用すべきでない理由sys.setdefaultencoding('utf8')

これは厄介なハックです( を使用しなければならない理由がありますreload)。問題を隠蔽し、Python 3.xへの移行を妨げるだけです。問題を理解し、根本的な原因を修正して、Unicode zenを楽しんでください。py スクリプトで sys.setdefaultencoding("utf-8") を使用しないのはなぜですか?詳細は

おすすめ記事