2

いくつかのテストの後、以下の最小限の test.py スクリプトの誤動作を制限することができました。

# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"

注: test.py は ISO-8859-1 (つまり latin-1) でエンコードされています。つまり、"é" は "\xe9" に等しく、"î" は "\xee" に等しくなります。

D:\test>python --version
Python 2.7.3
D:\test>python test.py
Vérifier l'affichage de cette chaîne
D:\test>python test.py > test.log
Traceback (most recent call last):
  File "test.py", line 2, in <module>
    print u"VÚrifier l'affichage de cette cha¯ne"
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128)

質問は次のとおりです。

標準出力がコンソールに送られるか、リダイレクトされるか、他の何かにパイプされるかに関係なく、ユニコード文字列を印刷するときにpythonが同じように動作しないのはなぜですか?

4

2 に答える 2

4

まず、ISO-8859-1有効なコーディング宣言ではありません。あなたがしたいiso-8859-1ドキュメントを見ると、これlatin_1iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, またはと呼ぶことができますが、 とL1は言えませんISO-8859-1

codecs.lookup大文字と小文字を区別しない検索を行うなど、不適切な入力を受け入れるために後方に曲がっているように見えます。codecs.lookupまでたどる_codecs.lookup_PyCodec_Lookup、次のコメントが表示されます。

/* Convert the encoding to a normalized Python string: all
   characters are converted to lower case, spaces and hyphens are
   replaced with underscores. */

ただし、ソース ファイルのデコードは、同じコーデック ルックアップ プロセスを経由しません。実行時ではなくコンパイル時に発生するため、そうする理由はありません。(とにかく、「ドキュメントが間違っていると言っているのに、うまくいくように見える…では、なぜうまくいかないのですか?」と言うのは、そもそもばかげています。)

たとえば、2 つの Latin-1 ファイルを作成すると、次のようになります。

悪いコード.py:

# -*- coding: ISO-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"

グッドコード.py:

# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"

1 つ目は失敗し、2 つ目は成功します。

さて、なぜそれはコンソールに行くときに「動作」するのに、パイプされると例外が発生するのでしょうか?

Windows コンソールまたは Unix TTY に出力する場合、Python には、使用する正しいエンコーディングを推測するためのコードがいくつかあります。(Windows の裏で何が起こっているのかはわかりません。私が知っている限りでは、UTF-16 出力を使用している可能性さえあります。) コンソール/TTY に印刷していない場合、これを行うことはできません。エンコーディングを明示的に指定する必要があります。

sys.stdout.isatty()sys.stdout.encoding、およびを見ると、何が起こっているかがわかりますsys.getdefaultencoding()。さまざまなケースで Mac に表示されるのは次のとおりです。

  • Python 2、リダイレクトなし:True, UTF-8, ascii, Vérifier
  • Python 3、リダイレクトなし:True, UTF-8, utf-8, Vérifier
  • Python 2、リダイレクト:False, None, ascii, UnicodeEncodeError
  • Python 3、リダイレクト:False, UTF-8, utf-8, Vérifier

の場合isatty()encodingTTY の適切なエンコーディングになります。それ以外の場合encodingは、デフォルト値になります。これは、2.x ではNone(つまり)、(コードを確認する必要があると思います) 3.xasciiに基づくものです。getdefaultencoding()つまり、 が 2.x で TTY でないときに Unicode を印刷しようとすると、 ,stdoutとしてエンコードしようとしますが、非 ASCII 文字があると失敗します。asciistrict

使用するコーデックがどういうわけかわかっている場合は、Unicode を印刷しようとする代わりに、印刷するたびisatty()にそのコーデック (または、必要に応じて の代わりに ) をチェックしてエンコードすることasciiによりignore、手動でこれに対処できます。strict(必要なコーデックがわかっている場合は、3.x でもこれを行うことができます。たとえば、Windows-1252 ファイルを生成しようとしている場合、UTF-8 をデフォルトに設定してもあまり役に立ちません…)

そこの違いは、実際には Latin-1 とは何の関係もありません。これを試してください:

nocode.py:

print u"V\xe9rifier l'affichage de cette cha\xeene"
print u"V\u00e9rifier l'affichage de cette cha\u00eene"

Mac ターミナルでは UTF-8 にエンコードされた Unicode 文字列を取得し、Windows コマンド ウィンドウでは (明らかに) Windows-1252 にエンコードされますが、例外がファイルにリダイレクトされます。

于 2012-12-17T23:00:22.650 に答える
0

ここに来て、python の print() への「スマートにならないでください」スイッチを探し、答えが読み取り専用変数へのヒントを提供するので、「標準出力が utf-8 を処理できると python に信じさせる」スニペットを次に示します。

import sys, codecs

# somewhere in the function you need it or global main():
sys.stdout = codecs.open('/dev/stdout', encoding='utf-8', mode='w', errors='strict')

そこで、python はそれが tty か、tee(1) か、ファイル リダイレクトか、それともただの cat(1) かを気にしなくなりました。

于 2015-02-01T19:04:25.737 に答える