web-dev-qa-db-ja.com

UTF-8でエンコードされたテキストをPython <3?

私はすべてのロケールがUTF-8である最近のLinuxシステムを実行しています。

LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
...
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

次に、UTF-8でエンコードされたコンテンツをコンソールに書き込みたいと思います。

現在、PythonはFSエンコーディングにUTF-8を使用していますが、デフォルトのエンコーディングにはASCIIを使用しています:

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> sys.getfilesystemencoding()
'UTF-8'

これを行うための最良の(クリーンな)方法は、PYTHONIOENCODING環境変数を設定することだと思いました。しかし、Pythonはそれを無視しているようです。少なくとも私のシステムでは、envvarを設定した後でも、デフォルトのエンコーディングとしてasciiを取得し続けます。

# tried this in ~/.bashrc and ~/.profile (also sourced them)
# and on the commandline before running python
export PYTHONIOENCODING=UTF-8

スクリプトの開始時に次の操作を行うと、機能します。

>>> import sys
>>> reload(sys)  # to enable `setdefaultencoding` again
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("UTF-8")
>>> sys.getdefaultencoding()
'UTF-8'

しかし、そのアプローチは汚れているようです。それで、これを達成する良い方法は何ですか?

Workaround

デフォルトのエンコーディングを変更する代わりに-良いアイデアではありません(メジリアックの答えを参照)-sys.stdoutStreamWriter このような:

sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

それを処理する小さなユーティリティ関数については---(this Gist を参照してください。

47
Brutus

UTF-8でエンコードされたテキストをコンソールにPython <3?

print u"some unicode text \N{EURO SIGN}"
print b"some utf-8 encoded bytestring \xe2\x82\xac".decode('utf-8')

つまり、Unicode文字列がある場合は、直接印刷します。バイト文字列がある場合は、最初にUnicodeに変換します。

ロケール設定(LANGLC_CTYPE)はutf-8ロケールを示しているため、理論的にはutf-8バイト文字列を直接印刷でき、ターミナルに正しく表示されるはずです(ターミナル設定がロケール設定である必要があります)、それを避ける必要があります:スクリプト内の環境の文字エンコーディングをハードコードしないでください; 代わりにUnicodeを直接印刷します

あなたの質問には多くの間違った仮定があります。

Unicodeを端末に出力するために、ロケール設定でPYTHONIOENCODINGを設定する必要はありません。 utf-8ロケールはすべてのUnicode文字をサポートします。つまり、そのまま動作します。

回避策sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)は必要ありません。一部のコード(制御しない)がバイトを印刷する必要がある場合、および/または nicodeをWindowsコンソールに印刷する(誤ったコードページ、デコードできない文字を印刷できない) の場合、破損する可能性があります。正しいロケール設定および/またはPYTHONIOENCODING envvarで十分です。また、sys.stdoutを置き換える必要がある場合は、 codecsモジュールの代わりにio.TextIOWrapper()を使用してくださいwin-unicode-console package と同様です。

sys.getdefaultencoding()は、ロケール設定およびPYTHONIOENCODINGとは無関係です。 PYTHONIOENCODINGの設定がsys.getdefaultencoding()を変更するという仮定は誤りです。代わりにsys.stdout.encodingを確認する必要があります。

コンソールに印刷する場合、sys.getdefaultencoding()は使用されません。 PYTHOHIOENCODINGが設定されていない限り、stdoutがファイル/パイプにリダイレクトされる場合、Python 2のフォールバックとして使用できます。

$ python2 -c'import sys; print(sys.stdout.encoding)'
UTF-8
$ python2 -c'import sys; print(sys.stdout.encoding)' | cat
None
$ PYTHONIOENCODING=utf8 python2 -c'import sys; print(sys.stdout.encoding)' | cat
utf8

sys.setdefaultencoding("UTF-8");を呼び出さないでください。データが破損する可能性があります黙っておよび/または予期しないサードパーティのモジュールが破損する可能性があります。 sys.getdefaultencoding()は、バイト文字列(str)とunicode in Python 2 暗黙的にたとえば"a" + u"b"との間の変換に使用されます。また、 @ mesilliacの答えの引用

8
jfs

これを達成することは推奨されません。

Fedoraは システムロケールをデフォルトとして使用 を提案しましたが、明らかにこれは他のことを壊します。

メーリングリストの議論 からの引用です:

 Pythonでサポートされているデフォルトのエンコーディングは、
 
 Python 2.x:ASCII 
 Python 3.x:UTF-8 
 
これらを変更すると、あなたは自分自身であり、奇妙なことが
開始しますデフォルトのエンコーディングは、
 Pythonと外界との間の変換だけでなく、
 8ビット文字列とUnicode間のすべての内部変換にも影響します。 。
 
 pangoモジュールで行われていることのようにハックします(
を取得するためにサイトモジュールを
 sys.setdefaultencoding()API back)はまさに
まったく間違っており、Unicode 
オブジェクトがデフォルトのエンコードされた表現をキャッシュするため、深刻な問題を引き起こします。
 
しないでくださいロケールベースのデフォルトエンコーディングの使用を有効にします。
 
達成したいのが、
 stdoutおよびstdinのエンコーディングをパイプ用に正しく設定することだけなら、
 instこれらの(のみ)の.encoding属性を変更します。
 
-
 Marc-Andre Lemburg 
 eGenix.com 
28
mesilliac

これは私がそれを行う方法です:

#!/usr/bin/python2.7 -S

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

Banglineの-Sに注意してください。これは、Python=自動的にsiteモジュールをインポートしないようにします。siteモジュールは、デフォルトのエンコードを設定し、メソッドを削除して、ただし、既に設定されているものは尊重されます。

23
Keith

プログラムが画面に適切な文字、つまり無効なシンボルを表示しない場合、次のコマンドラインでプログラムを実行します。

PYTHONIOENCODING=utf8 python3 yourprogram.py

または、プログラムがグローバルにインストールされたモジュールの場合、次のようになります。

PYTHONIOENCODING=utf8 yourprogram

一部のプラットフォームでは、Cygwin(mintty.exeターミナル)Anaconda Python(またはPython 3)、単にexport PYTHONIOENCODING=utf8以降、プログラムを実行しても動作しません。常に毎回実行する必要がありますPYTHONIOENCODING=utf8 yourprogramプログラムを正しく実行します。

Linuxでは、Sudoの場合、-E引数を使用して、ユーザー変数をSudoプロセスにエクスポートします。

export PYTHONIOENCODING=utf8
Sudo -E python yourprogram.py

これを試してもうまくいかなかった場合は、Sudo Shellを起動する必要があります。

Sudo /bin/bash
PYTHONIOENCODING=utf8 yourprogram

関連する:

  1. Python <3? でコンソールにUTF-8エンコードされたテキストを印刷する方法
  2. Pythonのデフォルトエンコーディングを変更しますか?
  3. cp1252にUTF-8を強制する(Python3)
  4. 永続的に設定Python Cygwin内のAnacondaのパス
  5. https://superuser.com/questions/1374339/what-does-the-e-in-Sudo-e-do
  6. なぜbash -c 'var = 5 printf "$ var"'は5を出力しないのですか?
  7. https://unix.stackexchange.com/questions/296838/whats-the-difference-between-eval-and-exec
3
user