[Python-ml-jp 3250] Re: unicodeを含む文字列の print
Tamito KAJIYAMA
RD6T-KJYM @ j.asahi-net.or.jp
2005年 3月 28日 (月) 21:02:29 JST
梶山です。
>具体的にはunicode文字列をprintするとき、ターミナルでは正常に動作
>するのですが、ファイルにリダイレクトしようとするとエラーとなります。
結論から言いますと、
print "try '%s' in %s (%s)" % (s0, enc1, " ".join(map(lambda c:"%02x" % ord(c), s)))
の s0 のところを
repr(s0)
または
s0.encode(sys.getfilesystemencoding())
とすればリダイレクトしてもしなくても同じ結果になると思います。
>UnicodeEncodeError: 'ascii' codec can't encode characters in position
>5-9: ordinal not in range(128)
>
>のようにunicodeを含む文字列をprintするところでエラーとなってしまいます。
>これはなぜでしょうか?
端的に言うと、"ascii" コデックで変換できない文字列を変換しようとしている
からです。これは Python で Unicode を使うときにありがちな実行時エラーで、
多くの場合「暗黙のエンコード」が起こっていることを意味します。
暗黙のエンコードとは、unicode オブジェクトから string オブジェクトへの
変換が必要な場面で、エンコード名が陽に指定されていないために「デフォルトの
エンコード名」が用いられることです。デフォルトのエンコード名は、多くの場合
"ascii" になっています。上のエラーメッセージでも "ascii" が使われていますね。
また、
(1) python encdet.py
だとエラーにならず、
(2) python encdet.py > foo
だとエラーとなるのは、デフォルトのエンコード名が変わっているからです。
この場合、リダイレクトするか否かによって標準出力(一種のファイルオブジェクト)の
属性の一つである「ファイルエンコーディング」が変化します。
標準出力のファイルエンコーディングは sys.stdout.encoding で参照できます。
(1) の場合、sys.stdout.encoding の値は sys.getfilesystemencoding() の
値 (例えば、LANG=ja_JP.eucJP な環境では "eucJP") になるようです。
(2) の場合、sys.stdout.encoding の値は None になるようです。
このファイルエンコーディングに従ってデフォルトのエンコード名が決定されて
いるようです。恐らくsys.stdout.encoding の値をデフォルトのエンコード名として
使い、None のときは "ascii" を使うようになっているのだろうと推測します。
print 文で unicode オブジェクトをいきなり印字するというのは暗黙のエンコーディングに
頼るということなので、今回のように環境や実行方法によっては動作しなくなるのです。
結論としては、unicode オブジェクト s0 を print 文で印字するときは
print repr(s0)
のように unicode→string 変換が起こらないようにする、または
print s0.encode(sys.getfilesystemencoding())
のように陽にエンコード名を指定するのが無難です。
--
KAJIYAMA, Tamito <RD6T-KJYM @ asahi-net.or.jp>
>初めまして。小林と申します。
>Pythonはまだリファレンスブック片手の初心者です。
>
>現在、pythonを使用した簡単なスクリプトを作成していますが、以下のよ
>うな問題で悩んでます。ml書庫を探した限りでは解決の糸口が掴めなかっ
>たので、教えていただければと思います。
>
>具体的にはunicode文字列をprintするとき、ターミナルでは正常に動作
>するのですが、ファイルにリダイレクトしようとするとエラーとなります。
>
>たとえば他人のプログラムで申し訳ありませんが、
>http://www.unixuser.org/~euske/python/index-j.html
>にある新山さんの encdet.py をターミナルシェル上で実行すると問題な
>く動作しますが、
>
>$ python ./encdet.py > foo
>
>とすると(メールの都合上折り返してます。)
>
>Traceback (most recent call last):
> File "./encdet.py", line 338, in ?
> test_suite(); sys.exit(0)
> File "./encdet.py", line 326, in test_suite
> test(u"\uffff\uffff\uffff\uffff\uffff\u0242\uffff\uffff\uffff",
>["japanese.euc_jp", "japanese.ms932", "utf8"])
> File "./encdet.py", line 308, in test
> print "try '%s' in %s (%s)" % (s0, enc1, " ".join(map(lambda
>c:"%02x" % ord(c), s)))
>UnicodeEncodeError: 'ascii' codec can't encode characters in position
>5-9: ordinal not in range(128)
>
>のようにunicodeを含む文字列をprintするところでエラーとなってしまいます。
>これはなぜでしょうか?
>
>実行環境は FedoraCore3 + python2.3.4 及び NetBSD2.0 + python2.4
>で確認してみました。
>
>うまくドキュメントが読めていないのかもしれませんが、解決のポインタ
>など教えていただけると幸いです。
>
>以上、よろしくお願いいたします。
Python-ml-jp メーリングリストの案内