cp932で表現できない文字がたまに混ざるユニコード文字列をWindowsのコンソールにprintしたい場合

こんな質問を受けました

Windows上のPython2.7を使っていて、手軽なデバッグ出力にprint文を使っているのだが、表示しようとしたユニコード文字列xにcp932で表現できない文字が含まれているとUnicodeEncodeErrorになってしまう。明示的にx.encode('cp932', 'replace')とかすれば大丈夫だが、全部の箇所にこれを書いて回るのはやりたくない。何かいい方法はないか?

えっと、僕はMacを使っててコンソールもUTF-8なので問題ありません(ぇ

というのはさておき、print文でユニコード文字列を表示しようとした際には、そのユニコード文字列を端末のエンコーディングでバイト列に変換(encode)しようとする。この時、デフォルトでは「変換できない文字があったら例外を投げる」(strict)モードになっている。

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print u"\ufffe"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'cp932' codec can't encode character u'\ufffe' in position 0: illegal multibyte sequence 

なので、「変換できない文字があったら適当に置き換える」(replace)モードのStreamWriterを作ったらいいんじゃないかと思った。

>>> import codecs
>>> import sys
>>> codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='replace')
<encodings.cp932.StreamWriter object at 0x00BC1470>
>>> sys.stdout = _
>>> print u"あ\ufffeあ"
あ?あ

ちなみに適当な文字で置き換える(replace)だけでなく、XML参照に置き換えたり(xmlcharrefreplace)、バックスラッシュ表現に置き換えたり(backslashreplace)することもできる。また、ignoreだと無視しstrictだと例外を投げる。

>>> import sys, codecs
>>> sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='xmlcharrefreplace')
>>> print u"あ\ufffeあ"
あ&#65534;あ
>>> import sys, codecs
>>> sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='backslashreplace')
>>> print u"あ\ufffeあ"
あ\ufffeあ
>>> import sys, codecs
>>> sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='ignore')
>>> print u"あ\ufffeあ"
ああ


あわせて読みたい: UnicodeDecodeError/UnicodeEncodeErrorに悩まないPython 2.x プログラミング - atsuoishimotoの日記(トラックバックを飛ばしてモヒカンなツッコミを待つライフハック)