Python、Unicode、およびWindowsコンソール


146

WindowsコンソールでUnicode文字列を印刷しようとすると、UnicodeEncodeError: 'charmap' codec can't encode character ....エラーが発生します。これは、WindowsコンソールがUnicodeのみの文字を受け入れないためだと思います。これを回避する最良の方法は何ですか??この状況で失敗するのではなく、Pythonに自動的にを印刷させる方法はありますか?

編集: 私はPython 2.5を使用しています。


注:チェックマークの付いた@ LasseV.Karlsenの回答は(2008年から)少し古くなっています。以下の解決策/回答/提案を慎重に使用してください!!

@JFSebastianの回答は、今日(2016年1月6日)より関連性が高くなります。


Pythonのどのバージョンを使用していますか?2.4.3でこの問題が解決され、2.4.4で修正されたとの言及がありました。
スチュ


これをチェックてください。
Soorena 2016

1
私が見つけた最も簡単な答えは次のように入力することです:cmdでpyhtonを使用する前にchcp 65001
Soorena

1
次に、承認済みの回答を変更する必要があります...
Mr_and_Mrs_D

回答:


38

注:この回答は古くなっています(2008年以降)。以下のソリューションを注意して使用してください!!


問題と解決策の詳細を示すページは次のとおりです(このページでテキストsys.stdoutをインスタンスにラッピングで検索してください)。

PrintFails-Python Wiki

そのページからのコードの抜粋を次に示します。

$ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line'
  UTF-8
  <type 'unicode'> 2
  Б
  Б

  $ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line' | cat
  None
  <type 'unicode'> 2
  Б
  Б

そのページには、さらに読む価値のあるいくつかの情報があります。


7
リンクは切れており、回答の要旨は引用されていません。-1
0xC0000022L 2013年

1
ラッピングについてのアドバイスを試してみると、sys.stdout間違ったものを出力します。たとえば、en-dashの代わりにu'\u2013'なりûます。
user2357112はモニカ

@ user2357112新しい質問を投稿する必要があります。Unicodeとシステムコンソールは必ずしも最適な組み合わせではありませんが、私はこれについて十分に知りません。そのため、明確な答えが必要な場合は、SOに質問を投稿してください。
ラッセV.カールセン2014

2
リンクが停止しています。などのコードページ(OEM)がなどのcp437Windows ANSIコードページと異なるWindowsコンソールでは、コード例は間違っていますcp1252。コードが修正されないUnicodeEncodeError: 'charmap' codec can't encode characterエラーをし、文字化けなどにつながる可能性があり、ا©静かに置き換えられます╪º⌐
jfs 2015

73

更新: Pythonの3.6実装PEP 528:UTF-8にエンコード変更WindowsコンソールWindows上のデフォルトのコンソールは現在、すべてのUnicode文字を受け入れます。内部的には、下記win-unicode-consoleパッケージと同じUnicode APIを使用しいますprint(unicode_string)今すぐ機能するはずです。


私が取得UnicodeEncodeError: 'charmap' codec can't encode character... エラー。

エラーは、印刷しようとしているUnicode文字が、現在の(chcp)コンソール文字エンコードを使用して表現できないことを意味します。コードページは、多くの場合、8ビットのエンコーディングでありcp437、1MのUnicode文字から0x100文字までしか表現できません。

>>> u "\ N {ユーロ記号}"。encode( 'cp437')
トレースバック(最新の呼び出しが最後):
...
UnicodeEncodeError: 'charmap'コーデックは位置0の文字 '\ u20ac'をエンコードできません:
キャラクターマップ 

これは、WindowsコンソールがUnicodeのみの文字を受け入れないためだと思います。これを回避する最良の方法は何ですか?

WindowsコンソールはUnicode文字を受け入れ、対応するフォントが設定されている場合は、それらを表示することもできます(BMPのみ)。@Daira Hopwoodの回答でWriteConsoleW()提案されているように、APIを使用する必要があります。これは透過的に呼び出すことができます。つまり、win-unicode-consolepackageを使用する場合、スクリプトを変更する必要はなく、変更する必要もありません。

T:\> py -mpip install win-unicode-console
T:\> py -mrun your_script.py

参照のPython 3.4、ユニコード、異なる言語とWindowsとの契約は何?

?この状況で失敗するのではなく、Pythonに自動的にを印刷させる方法はありますか?

すべてのエンコードできない文字を?あなたのケースで置き換えるだけで十分な場合は、PYTHONIOENCODINGenvvarを設定できます:

T:\> set PYTHONIOENCODING=:replace
T:\> python3 -c "print(u'[\N{EURO SIGN}]')"
[?]

Python 3.6以降では、PYTHONIOENCODINGenvvarがPYTHONLEGACYWINDOWSIOENCODING空でない文字列に設定されていない限り、envvarで指定されたエンコーディングはインタラクティブコンソールバッファーでは無視されます。


3
「WindowsのデフォルトのコンソールはすべてのUnicode文字を受け入れるようになります」しかし、コンソールを構成する必要があります。(cmdまたはpython IDLEの)ウィンドウの上部を右クリックし、default / fontで「Lucida console」を選択します。(日本語と中国語は私にはうまくいきませんが、私はそれなしで生き残る必要があります...)
JinSnow 2017年

2
@ギラウム:回答には、Windowsコンソールに関する太字のフレーズが含まれています。この答えは、IDLEを言及していないが、あなたはそれでフォントを設定する必要はありません(私はデフォルトではIDLEでうまく日本語と中国語の文字を参照してください。試してみてくださいprint('\u4E01')print('\u6b63'))。
jfs 2017年

2
@Guillaume Windows 10に言語パックをインストールすると、中国語を取得することもできます。中国語をサポートするコンソールフォントが追加されました。
Mark Tolonen 2017年

28

コードページを65001に変更することを提案する他のもっともらしいサウンドの回答にもかかわらず、それは機能しません。(また、使用してエンコードするデフォルト値を変更することはsys.setdefaultencodingある良い考えではありません。)

参照してくださいこの質問内容及び作業を行うコードのために。


2
win-unicode-consolePythonパッケージ(コードに基づく)では、py -mrun your_script.pycommandを使用してUnicodeを直接出力する場合、スクリプトの変更を回避できます。
jfs 2016

12

悪い文字の信頼できる表現を取得することに興味がない場合は、次のようなものを使用することができます(3.xを含むpython> = 2.6で作業します)。

from __future__ import print_function
import sys

def safeprint(s):
    try:
        print(s)
    except UnicodeEncodeError:
        if sys.version_info >= (3,):
            print(s.encode('utf8').decode(sys.stdout.encoding))
        else:
            print(s.encode('utf8'))

safeprint(u"\N{EM DASH}")

文字列内の不正な文字は、Windowsコンソールで印刷可能な表現に変換されます。


.encode('utf8').decode(sys.stdout.encoding)u"\N{EM DASH}".encode('utf-8').decode('cp437')->ΓÇö
jfs

単にprint(s.encode('utf-8'))コンパイラエラーを回避するためのより良い方法かもしれません。代わりに、印刷できない文字の\ xNN出力を取得します。これは、私の診断メッセージには十分でした。
CODE-REaD 2016年

4
これは非常に、見事に間違っています。UTF-8にエンコードしてから8ビット文字セットとしてデコードすると、a)失敗することが多く、すべてのコードページに256バイト値すべての文字があるわけではありません。b)データの解釈が常に間違っているため、代わりにMojibakeの混乱が生じます。
Martijn Pieters

10

以下のコードは、WindowsでもPython出力をUTF-8としてコンソールに出力します。

コンソールはWindows 7では文字を適切に表示しますが、Windows XPでは適切に表示しませんが、少なくとも機能し、すべてのプラットフォームでスクリプトから一貫した出力を得ることが最も重要です。出力をファイルにリダイレクトできます。

以下のコードは、Windows上のPython 2.6でテストされました。


#!/usr/bin/python
# -*- coding: UTF-8 -*-

import codecs, sys

reload(sys)
sys.setdefaultencoding('utf-8')

print sys.getdefaultencoding()

if sys.platform == 'win32':
    try:
        import win32console 
    except:
        print "Python Win32 Extensions module is required.\n You can download it from https://sourceforge.net/projects/pywin32/ (x86 and x64 builds are available)\n"
        exit(-1)
    # win32console implementation  of SetConsoleCP does not return a value
    # CP_UTF8 = 65001
    win32console.SetConsoleCP(65001)
    if (win32console.GetConsoleCP() != 65001):
        raise Exception ("Cannot set console codepage to 65001 (UTF-8)")
    win32console.SetConsoleOutputCP(65001)
    if (win32console.GetConsoleOutputCP() != 65001):
        raise Exception ("Cannot set console output codepage to 65001 (UTF-8)")

#import sys, codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
sys.stderr = codecs.getwriter('utf8')(sys.stderr)

print "This is an Е乂αmp١ȅ testing Unicode support using Arabic, Latin, Cyrillic, Greek, Hebrew and CJK code points.\n"

1
別のコンソールを使用するだけでこれを回避する方法はありますか?
内部石2011

@sorin:なぜ最初import win32consoleにaの外でtry、後で条件付きでaの中で行うのtryですか?そのような意味がない(最初のimport
0xC0000022L

価値があるのは、David-Sarah Hopwoodによって提供されたものです(win32拡張モジュールのインストールを気にしていなかったため、実行することもできませんでした)
Jaykul

4
システムのデフォルトのエンコーディングを変更しないでください。代わりにUnicode値を修正してください。デフォルトのエンコーディングを変更すると、デフォルトの動作に依存しているライブラリが壊れる可能があります。これを行う前に、モジュールを強制的にリロードする必要があるのには理由があります。
Martijn Pieters

7

pythonスクリプトを実行する前に、このコードをコマンドラインに入力するだけです。

chcp 65001 & set PYTHONIOENCODING=utf-8

5

GiampaoloRodolàの答えと同様ですが、もっと汚いです。私は本当に、エンコーディングの主題全体とそれらがWindozeコンソールにどのように適用されるかを理解するために、長い間(すぐに)費やすつもりです。

今のところ、プログラムがクラッシュしないことを意味するsthgが欲しかったし、理解しました。また、あまりにも多くのエキゾチックなモジュールをインポートする必要がなかった(特に、Jythonを使用しているため、Pythonの半分の時間)モジュールは実際には利用可能ではないことがわかります)。

def pr(s):
    try:
        print(s)
    except UnicodeEncodeError:
        for c in s:
            try:
                print( c, end='')
            except UnicodeEncodeError:
                print( '?', end='')

NB "pr"は "print"よりもタイプが短い(そして "safeprint"よりもかなり短い)...!


賢い、問題を回避するための迅速で汚い方法。これは断続的な解決策には最適だと思います。
JFA 2016

3

Python 2の場合:

print unicode(string, 'unicode-escape')

Python 3の場合:

import os
string = "002 Could've Would've Should've"
os.system('echo ' + string)

またはwin-unicode-consoleを試してください:

pip install win-unicode-console
py -mrun your_script.py

2

TL; DR:

print(yourstring.encode('ascii','replace'));

私はこれに遭遇し、Twitchチャット(IRC)ボットに取り組んでいました。(Python 2.7最新)

応答するためにチャットメッセージを解析したかった...

msg = s.recv(1024).decode("utf-8")

しかし、人間が読める形式で安全にコンソールに出力します。

print(msg.encode('ascii','replace'));

これにより、ボットがUnicodeEncodeError: 'charmap'エラーをスローする問題が修正され、Unicode文字がに置き換えられました?


2

あなたの問題の原因は、Unicodeを受け入れようとしないWinコンソールではありません(デフォルトでWin2kを推測しているため、これは可能です)。これはデフォルトのシステムエンコーディングです。このコードを試して、何が得られるかを確認してください。

import sys
sys.getdefaultencoding()

asciiと表示されている場合は、原因があります;-) sitecustomize.pyというファイルを作成してpythonパスの下に配置する必要があります(/usr/lib/python2.5/site-packagesの下に配置しますが、それはWin-それはc:\ python \ lib \ site-packagesなどです)、次の内容で:

import sys
sys.setdefaultencoding('utf-8')

そしておそらくあなたもあなたのファイルにエンコーディングを指定したいかもしれません:

# -*- coding: UTF-8 -*-
import sys,time

編集:詳細については、Dive into Pythonブックをご覧ください。


2
setdefaultencoding()はsysではもうありません(モジュールドキュメントによるとv2.0以降)。
Jon Cage

現時点では証明できませんが、このトリックを後のバージョン(Windowsの2.5)で使用したことがわかっています。
BartoszRadaczyński2009

6
OK、しばらくして、次のことに気づきました。「この関数は、サイトモジュールの実装と、必要に応じてsitecustomizeでのみ使用することを目的としています。サイトモ​​ジュールで使用されると、sysモジュールの名前空間から削除されます。 」
BartoszRadaczyński、2009年

4
実際には、Windowsコンソールをutf-8に設定できます。あなたはchcp 65001と言う必要があり、それはユニコードになります。
BartoszRadaczyński10年

4
明確にするために、デフォルトのエンコーディングを変更することは非常に悪い考えです。これは、医者に骨を正しくセットしてもらうのではなく、骨折した足をたたいて、何も起こらなかったかのように歩くのと同じです。Unicodeテキストを処理するすべてのコードは、暗黙的なエンコード/デコードに依存するのではなく、一貫してそうする必要があります。
Martijn Pieters

1

JFセバスチャンの回答に関連するようなものですが、もっと直接的です。

コンソール/ターミナルに出力するときにこの問題が発生している場合は、次のようにしてください。

>set PYTHONIOENCODING=UTF-8

3
set PYTHONIOENCODING=UTF-8コンソールがcp437などの別のエンコーディングを使用している場合、mojibakeが発生する可能性があります。cp65001さまざまな問題があります。UnicodeをWindowsコンソールに出力するにWriteConsoleW()は、私の回答で提案されているように、Unicode APIを使用する必要がありPYTHONIOENCODINGます。?WriteConsoleW()でも、このような文字の作品を)。PYTHONIOENCODING出力がファイルにリダイレクトされる場合に使用できます。
JFS

1

Python 3.6 windows7:pythonコンソール(pythonロゴが付いている)またはwindowsコンソール(cmd.exeと書かれている)を使用して、pythonを起動する方法がいくつかあります。

Windowsコンソールでutf8文字を印刷できませんでした。utf-8文字を印刷すると、次のエラーが発生します。

OSError: [winError 87] The paraneter is incorrect 
Exception ignored in: (_io-TextIOwrapper name='(stdout)' mode='w' ' encoding='utf8') 
OSError: [WinError 87] The parameter is incorrect 

上の答えを理解しようとして失敗した後、私はそれが設定の問題にすぎないことを発見しました。コマンドコンソールウィンドウの上部を右クリックし、タブでfontlucidaコンソールを選択します。


0

ジェームス・スラックは尋ねました、

Pythonに自動的に印刷させる方法はありますか?この状況で失敗するのではなく?

他のソリューションでは、Windows環境を変更するか、Pythonの print()機能をます。以下の答えは、Sulakの要求を満たすために近づいています。

Windows 7では、Python 3.5は、 UnicodeEncodeError次のようにます。

    代わりに:     print(text)
    代替:     print(str(text).encode('utf-8'))

例外をスローする代わりに、Pythonは印刷不可能なUnicode文字を\ xNN 16進コードとして表示するようになりました。例:

  Halmalo n \ xe2 \ x80 \ x99 \ xc3 \ xa9tait plus qu \ xe2 \ x80 \ x99un point noir

の代わりに

  ハルマロネタイトプラスクアンポイントノワール

確かに、後者はceteris paribusが望ましいですが、それ以外の場合、前者は診断メッセージに対して完全に正確です。Unicodeをリテラルバイト値として表示するため、前者はエンコード/デコードの問題の診断にも役立ちます。

注:上記のstr()呼び出しが必要になるのは、そうしないencode()と、PythonがUnicode文字を数値のタプルとして拒否するためです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.