Python で stdout をパイプするときに正しいエンコーディングを設定する
-
20-08-2019 - |
質問
Python プログラムの出力をパイプするときに、Python インタープリターはエンコーディングについて混乱し、エンコーディングを None に設定します。これは次のようなプログラムを意味します。
# -*- coding: utf-8 -*-
print u"åäö"
通常に実行すると正常に動作しますが、次の場合は失敗します。
UnicodeEncodeエラー:「ascii」コーデックは位置 0 の文字 u'\xa0' をエンコードできません:序数が範囲外です(128)
パイプシーケンスで使用する場合。
配管時にこれを機能させる最善の方法は何ですか?シェル/ファイルシステム/その他が使用しているエンコーディングを使用するように指示することはできますか?
私がこれまでに見た提案は、site.py を直接変更するか、次のハックを使用してdefaultencodingをハードコーディングすることです。
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"
配管をうまく機能させるためのより良い方法はありますか?
解決
あなたのコードは動作します。あなたはパイピングされている場合、あなたはそれを自分でエンコードする必要があります。
親指のルールは:常に内部的にUnicodeを使用します。あなたが受け取るものをデコードし、あなたが送って何をエンコードます。
# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
もう一つの教訓的な例は、間に大文字のすべてを作り、ISO-8859-1とUTF-8の間で変換するPythonプログラムです。
import sys
for line in sys.stdin:
# Decode what you receive:
line = line.decode('iso8859-1')
# Work with Unicode internally:
line = line.upper()
# Encode what you send:
line = line.encode('utf-8')
sys.stdout.write(line)
システムのデフォルトエンコーディングを設定、使用するいくつかのモジュールやライブラリは、それがASCIIであるという事実に頼ることができるので、悪い考えです。それをしないでください。
他のヒント
まず、このソリューションに関してます:
# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')
これは、明示的に指定したエンコーディングで毎回を印刷するには実用的ではありません。これは、反復的でエラーが発生しやすくなります。
より良い解決策は、選択したエンコードでエンコードするために、あなたのプログラムの開始時にのsys.stdout
の変更することです。ここで私はのPythonで見つかった一つの解決策は以下のとおりです。どのようにSYSです選択した.stdout.encoding に、特定のコメントによる "とか":?
import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
あなたは、環境変数「UTF_8」を「PYTHONIOENCODING」に変更しようとする場合があります。私はこの問題に私の試練にページを書かれているにます。
Tlの、ブログ記事のDRます:
import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))
あなたに与えます。
utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
export PYTHONIOENCODING=utf-8
仕事をするが、パイソン自体にそれを設定することはできません...
設定されていない場合は、私たちにできることは確認しているとしてコールスクリプトの前にそれを設定するようにユーザーに指示します:
if __name__ == '__main__':
if (sys.stdout.encoding is None):
print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
exit(1)
コメントに返信するには更新します。 stdoutにパイプするときの問題は、単に存在します。 私は、Fedora 25のPython 2.7.13でテスト
python --version
Python 2.7.13
猫b.py
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
print sys.stdout.encoding
ランニング./b.py
UTF-8
ランニング./b.py |以下
None
私はhref="https://stackoverflow.com/questions/30857027/youtube-api-unicodeencodeerror-in-python-3-4">同様の問題先週の
ここでは私の修正します: PyCharmメニューバー最低料金:ファイル - >設定... - >エディタ - >ファイルエンコーディングは、その後、設定:「IDEエンコーディング」、「プロジェクトのエンコーディング」とALL UTF-8にし、「デフォルトエンコーディングをプロパティファイルのための」彼女は今、魔法のように動作します。 この情報がお役に立てば幸い!
クレイグ・マックイーンの答えの議論の余地消毒バージョンます。
import sys, codecs
class EncodedOut:
def __init__(self, enc):
self.enc = enc
self.stdout = sys.stdout
def __enter__(self):
if sys.stdout.encoding is None:
w = codecs.getwriter(self.enc)
sys.stdout = w(sys.stdout)
def __exit__(self, exc_ty, exc_val, tb):
sys.stdout = self.stdout
使用方法:
with EncodedOut('utf-8'):
print u'ÅÄÖåäö'
私はを呼び出して、それを「自動化」でした
def __fix_io_encoding(last_resort_default='UTF-8'):
import sys
if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
import os
defEnc = None
if defEnc is None :
try:
import locale
defEnc = locale.getpreferredencoding()
except: pass
if defEnc is None :
try: defEnc = sys.getfilesystemencoding()
except: pass
if defEnc is None :
try: defEnc = sys.stdin.encoding
except: pass
if defEnc is None :
defEnc = last_resort_default
os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding
はい、それはこの「のsetenv」が失敗した場合は、ここで無限ループを取得することが可能です。
ここで、何が起こっているのかを最終的に理解するまでに長い時間をかけて実験しなければならなかった何かについて言及しようと思いました。これはここにいる誰もがあまりにも明白なので、わざわざ言及しないかもしれません。でも、そうしてくれたら助かっただろうから、その原則で…!
注意:使っています ジトン 具体的には v 2.7 なので、これは当てはまらない可能性があります。 CPython...
注意2:私の .py ファイルの最初の 2 行は次のとおりです。
# -*- coding: utf-8 -*-
from __future__ import print_function
「%」 (別名「補間演算子」) 文字列構築メカニズムも追加の問題を引き起こします...「環境」のデフォルトのエンコーディングが ASCII で、次のようなことをしようとした場合
print( "bonjour, %s" % "fréd" ) # Call this "print A"
Eclipse での実行は難しくありません。Windows CLI (DOS ウィンドウ) では、エンコーディングが次のようになっていることがわかります。 コードページ850 (私の Windows 7 OS)または同様のものは、少なくともヨーロッパのアクセント文字を処理できるため、機能します。
print( u"bonjour, %s" % "fréd" ) # Call this "print B"
も機能します。
OTOH さん、CLI からファイルに直接アクセスすると、stdout エンコードは None になり、デフォルトで ASCII になります (私の OS ではとにかく)。これでは上記の出力のいずれも処理できません...(恐ろしいエンコードエラー)。
したがって、次を使用して標準出力をリダイレクトすることを考えるかもしれません
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
ファイルへの CLI パイプで実行してみてください...非常に奇妙なことに、上記の印刷 A は機能します...しかし、上記の print B はエンコード エラーをスローします。ただし、以下は問題なく動作します。
print( u"bonjour, " + "fréd" ) # Call this "print C"
私が(暫定的に)到達した結論は、 ユニコード 「u」プレフィックスを使用する文字列は、% 処理メカニズムに送信され、デフォルトの環境エンコーディングの使用が含まれるようです。 stdout をリダイレクトするように設定したかどうかは関係ありません。
これにどう対処するかは人々の選択の問題です。Unicode の専門家に、なぜこのようなことが起こるのか、私が何らかの方法で間違っているのか、これに対する望ましい解決策は何か、それが次の場合にも当てはまるかどうかを述べてもらいたいと思います。 CPython, 、Python 3 で起こるかどうかなど。
Ubuntu 12.10 および GNOME ターミナルでは、プログラムが stdout に出力しているとき、または他のプログラムのパイプにフックされているときにエラーは生成されません。ファイルエンコーディングと端末エンコーディングは両方とも UTF-8.
$ cat a.py
# -*- coding: utf-8 -*-
print "åäö"
$ python a.py
åäö
$ python a.py | tee out
åäö
使用しているOSとターミナルエミュレータは何ですか?私の同僚の中にも、使用時に同様の問題を抱えている人がいると聞きました。 iTerm 2 そしてOS X。iTerm 2 が原因である可能性があります。
アップデート:この答えは間違っています - 詳細についてはコメントを参照してください
私は、レガシー・アプリケーションでは、この問題に遭遇した、そして何が印刷された場所を特定することは困難でした。私はこのハックで自分自身を助けます:
# encoding_utf8.py
import codecs
import builtins
def print_utf8(text, **kwargs):
print(str(text).encode('utf-8'), **kwargs)
def print_utf8(fn):
def print_fn(*args, **kwargs):
return fn(str(*args).encode('utf-8'), **kwargs)
return print_fn
builtins.print = print_utf8(print)
私のスクリプトの先頭には、test.pyます:
import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)
これは、すべてのエンコーディングを使用するように印刷するには呼び出しを変更し、ので、あなたのコンソールはこれを印刷することに注意してください:
$ python test.py
b'Axwell \xce\x9b Ingrosso'