Python, Unicode และคอนโซล Windows


146

เมื่อฉันพยายามพิมพ์สายอักขระ Unicode ในคอนโซล Windows ฉันได้รับUnicodeEncodeError: 'charmap' codec can't encode character ....ข้อผิดพลาด ฉันถือว่านี่เป็นเพราะคอนโซล Windows ไม่ยอมรับอักขระ Unicode เท่านั้น อะไรคือวิธีที่ดีที่สุดในรอบนี้ มีวิธีใดบ้างที่ฉันจะทำให้ Python พิมพ์ a โดยอัตโนมัติ?แทนที่จะล้มเหลวในสถานการณ์นี้

แก้ไข: ฉันใช้ Python 2.5


หมายเหตุ: @ LasseV.Karlsen คำตอบที่มีเครื่องหมายถูกล้าสมัย (ตั้งแต่ปี 2008) โปรดใช้วิธีแก้ปัญหา / คำตอบ / คำแนะนำด้านล่างด้วยความระมัดระวัง !!

@JFSebastian คำตอบมีความเกี่ยวข้องมากขึ้น ณ วันนี้ (6 มกราคม 2559)


คุณเป็น Python เวอร์ชันใด ฉันเคยเห็นการอ้างอิงว่าสิ่งนี้เสียใน 2.4.3 และได้รับการแก้ไขใน 2.4.4
สตู

3
เกี่ยวข้อง: bugs.python.org/issue1602
jfs

ตรวจสอบนี้ออก
Soorena

1
คำตอบที่ง่ายที่สุดที่ฉันพบคือพิมพ์: chcp 65001 ก่อนที่จะใช้ pyhton ในคำสั่ง
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

1
เมื่อฉันลองคำแนะนำเกี่ยวกับการห่อsys.stdoutมันจะพิมพ์สิ่งที่ผิด ตัวอย่างเช่นu'\u2013'กลายเป็นûแทนที่จะเป็นเส้นประ
user2357112 รองรับ Monica

@ user2357112 คุณจะต้องโพสต์คำถามใหม่เกี่ยวกับเรื่องนั้น Unicode และคอนโซลระบบไม่จำเป็นต้องเป็นชุดค่าผสมที่ดีที่สุด แต่ฉันไม่รู้เรื่องนี้มากพอดังนั้นหากคุณต้องการคำตอบที่ชัดเจนให้โพสต์คำถามไว้ที่ SO เกี่ยวกับเรื่องนี้
Lasse V. Karlsen

2
ลิงก์ตาย ตัวอย่างรหัสไม่ถูกต้องสำหรับ Windows คอนโซลที่เพจรหัส (OEM) เช่นcp437มีความแตกต่างจาก Windows ANSI cp1252เพจรหัสเช่น รหัสไม่สามารถแก้ไขUnicodeEncodeError: 'charmap' codec can't encode characterข้อผิดพลาดและอาจนำไปสู่อาการภาษาต่างดาวเช่นจะถูกแทนที่ด้วยอย่างเงียบا©╪º⌐
jfs

73

อัปเดต: Python 3.6ใช้PEP 528: เปลี่ยนการเข้ารหัสคอนโซล Windows เป็น UTF-8 : ตอนนี้คอนโซลเริ่มต้นบน Windows จะยอมรับอักขระ Unicode ทั้งหมด ภายในจะใช้ Unicode API เช่นเดียวกับแพคเกจดังกล่าวนี้ ควรทำงานตอนนี้win-unicode-consoleprint(unicode_string)


ฉันได้รับUnicodeEncodeError: 'charmap' codec can't encode character... ข้อผิดพลาด

ข้อผิดพลาดหมายความว่าอักขระ Unicode ที่คุณพยายามพิมพ์ไม่สามารถแสดงโดยใช้การchcpเข้ารหัสอักขระคอนโซลปัจจุบัน ( ) เพจรหัสมักจะมีการเข้ารหัส 8 บิตเช่นcp437ที่สามารถแสดงได้เพียง ~ 0x100 อักขระจาก ~ 1M อักขระ Unicode:

>>> u "\ N {EURO SIGN}". การเข้ารหัส ('cp437')
Traceback (การโทรล่าสุดครั้งล่าสุด):
...
UnicodeEncodeError: ตัวแปลงสัญญาณ 'charmap' ไม่สามารถเข้ารหัสอักขระ '\ u20ac' ในตำแหน่ง 0:
ตัวละครแผนที่ไป 

ฉันถือว่านี่เป็นเพราะคอนโซล Windows ไม่ยอมรับอักขระ Unicode เท่านั้น อะไรคือวิธีที่ดีที่สุดในรอบนี้

หน้าต่างคอนโซลไม่ยอมรับอักขระ Unicode และยังสามารถแสดงให้พวกเขา (BMP เท่านั้น) ถ้าตัวอักษรที่สอดคล้องกันมีการกำหนดค่า WriteConsoleW()API ควรใช้เป็นข้อเสนอแนะในคำตอบของ @Daira เคย สามารถเรียกได้ว่าโปร่งใสนั่นคือคุณไม่จำเป็นต้องและไม่ควรแก้ไขสคริปต์ของคุณหากคุณใช้win-unicode-consoleแพ็คเกจ :

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

ดูการจัดการกับ Python 3.4, Unicode, ภาษาต่าง ๆ และ Windows คืออะไร

มีวิธีใดบ้างที่ฉันจะทำให้ Python พิมพ์ a โดยอัตโนมัติ?แทนที่จะล้มเหลวในสถานการณ์นี้

หากมันเพียงพอที่จะแทนที่อักขระที่ไม่สามารถถอดรหัสได้ทั้งหมด?ในเคสของคุณคุณสามารถตั้งค่าPYTHONIOENCODINGenvvar :

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

ใน Python 3.6+ การเข้ารหัสที่ระบุโดยPYTHONIOENCODINGenvvar จะถูกละเว้นสำหรับบัฟเฟอร์คอนโซลแบบโต้ตอบเว้นแต่PYTHONLEGACYWINDOWSIOENCODINGenvvar จะถูกตั้งค่าเป็นสตริงที่ไม่ว่างเปล่า


3
"คอนโซลเริ่มต้นบน Windows จะยอมรับอักขระ Unicode ทั้งหมด" แต่คุณต้องกำหนดค่าคอนโซล: คลิกขวาที่ด้านบนของหน้าต่าง (ของ cmd หรือ python IDLE) โดยค่าเริ่มต้น / แบบอักษรเลือก "Lucida console" (ญี่ปุ่นและจีนไม่ได้ผลสำหรับฉัน แต่ฉันควรจะอยู่รอดหากไม่มี ... )
JinSnow

2
@Gillaillaume: คำตอบมีวลีที่เป็นตัวหนาเกี่ยวกับคอนโซล Windows: "ถ้าตัวอักษรที่เกี่ยวข้องมีการกำหนดค่า" คำตอบนี้ไม่ได้พูดถึง IDLE แต่คุณไม่จำเป็นต้องกำหนดค่าตัวอักษรที่อยู่ในนั้น (ผมเห็นญี่ปุ่นและจีนตัวละครได้ดีในที่ว่างโดยค่าเริ่มต้น. ลองprint('\u4E01'), print('\u6b63'))
jfs

2
@Gillaillaume คุณสามารถรับภาษาจีนได้หากคุณติดตั้งชุดภาษาใน Windows 10 มันเพิ่มฟอนต์คอนโซลที่รองรับภาษาจีน
Mark Tolonen

28

แม้จะมีคำตอบที่เป็นไปได้ที่ทำให้เกิดเสียงอื่น ๆ ที่ขอแนะนำให้เปลี่ยนหน้ารหัส 65001 เพื่อที่ไม่ได้ทำงาน (นอกจากนี้การเปลี่ยนแปลงเริ่มต้นการเข้ารหัสโดยใช้sys.setdefaultencodingคือไม่ได้เป็นความคิดที่ดี .)

ดูคำถามนี้สำหรับรายละเอียดและรหัสที่ใช้งานได้


2
win-unicode-consoleแพคเกจหลาม (ตามรหัสของคุณ) จะช่วยให้หลีกเลี่ยงการปรับเปลี่ยนสคริปต์ของคุณถ้ามันพิมพ์ Unicode โดยตรงโดยใช้คำสั่งpy -mrun your_script.py
jfs

12

หากคุณไม่สนใจที่จะได้รับตัวละครที่ไม่ดีที่เชื่อถือได้คุณอาจใช้สิ่งนี้ (ทำงานกับ python> = 2.6 รวมถึง 3.x):

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

4
นี่เป็นสิ่งที่ผิดอย่างยิ่งใหญ่ การเข้ารหัส UTF-8 แล้วถอดรหัสเป็นชุดอักขระแบบ 8 บิต a) มักจะล้มเหลวไม่ใช่ codepages ทั้งหมดที่มีอักขระสำหรับค่า 256 ไบต์ทั้งหมดและ b) การตีความข้อมูลที่ผิดเสมอทำให้Mojibakeสับสนแทน
Martijn Pieters

10

รหัสด้านล่างจะทำให้ Python output เป็น console เป็น UTF-8 แม้ใน Windows

คอนโซลจะแสดงตัวอักษรได้ดีบน Windows 7 แต่บน Windows XP จะไม่แสดงผลได้ดี แต่อย่างน้อยมันก็จะทำงานได้และที่สำคัญที่สุดคุณจะได้ผลลัพธ์ที่สม่ำเสมอจากสคริปต์ของคุณในทุกแพลตฟอร์ม คุณจะสามารถเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์

โค้ดด้านล่างทดสอบกับ Python 2.6 บน Windows


#!/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
มีวิธีการหลีกเลี่ยงปัญหานี้เพียงแค่ใช้คอนโซลอื่นหรือไม่?
endolith

@ โซริน: ทำไมคุณimport win32consoleออกไปข้างนอกครั้งแรกtryและหลังจากนั้นคุณทำอย่างมีเงื่อนไขภายในtry? ไม่ใช่ประเภทที่ไร้สาระ (แรกimport)
0xC0000022L

สำหรับสิ่งที่คุ้มค่าสิ่งที่ David-Sarah Hopwood นำเสนอให้ใช้งานได้ (ฉันไม่ได้เรียกใช้สิ่งนี้แม้แต่เพราะฉันไม่ได้ใส่ใจในการติดตั้งโมดูลส่วนขยาย win32)
Jaykul

4
อย่าเปลี่ยนการเข้ารหัสเริ่มต้นของระบบ แก้ไขค่า Unicode ของคุณแทน การเปลี่ยนการเข้ารหัสเริ่มต้นสามารถทำลายห้องสมุดที่พึ่งพาคุณรู้ว่าการทำงานเริ่มต้น มีเหตุผลที่คุณต้องบังคับให้โหลดโมดูลก่อนจึงจะทำได้
Martijn Pieters

7

เพียงแค่ใส่รหัสนี้ในบรรทัดคำสั่งก่อนดำเนินการสคริปต์ python:

chcp 65001 & set PYTHONIOENCODING=utf-8

5

เช่นเดียวกับคำตอบของ Giampaolo Rodolà แต่ยิ่งสกปรก: ฉันตั้งใจจริง ๆ ที่จะใช้เวลานาน (เร็ว ๆ นี้) ในการทำความเข้าใจหัวข้อทั้งหมดของการเข้ารหัสและวิธีที่พวกเขาใช้กับ Windoze consoles

สำหรับช่วงเวลาที่ฉันต้องการ 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

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

สาเหตุของปัญหาของคุณไม่ใช่คอนโซล Win ที่ไม่ยอมรับ Unicode (เช่นนี้เนื่องจากฉันเดาว่า Win2k เป็นค่าเริ่มต้น) เป็นการเข้ารหัสระบบเริ่มต้น ลองใช้รหัสนี้และดูว่ามันให้อะไรคุณ:

import sys
sys.getdefaultencoding()

ถ้ามันบอกว่า ascii มีสาเหตุของคุณ ;-) คุณต้องสร้างไฟล์ที่ชื่อว่า sitecustomize.py และวางไว้ใต้เส้นทางของไพ ธ อน Win - มันคือ c: \ python \ lib \ site-packages หรืออะไรบางอย่าง) โดยมีเนื้อหาดังต่อไปนี้:

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

และบางทีคุณอาจต้องการระบุการเข้ารหัสในไฟล์ของคุณด้วย:

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

แก้ไข: ข้อมูลเพิ่มเติมสามารถพบได้ในหนังสือ Dive Into Python


2
setdefaultencoding () เป็น nolonger ใน sys (ณ v2.0 ตามโมดูลเอกสาร)
Jon Cage

ฉันไม่สามารถพิสูจน์ได้ในตอนนี้ แต่ฉันรู้ว่าฉันใช้เคล็ดลับนี้กับรุ่นใหม่กว่า - 2.5 บน Windows
Bartosz Radaczyński

6
ตกลงหลังจากนั้นซักพักฉันก็พบว่า: "ฟังก์ชั่นนี้มีวัตถุประสงค์เพื่อใช้งานโดยการติดตั้งโมดูลไซต์และในบางครั้งที่จำเป็นโดย sitecustomize เมื่อมีการใช้โดยโมดูลไซต์มันจะถูกลบออกจากเนมสเปซของโมดูล sys "
Bartosz Radaczyński

4
จริงๆแล้วคุณสามารถตั้งค่าคอนโซล windows เป็น utf-8 คุณต้องบอกว่า chcp 65001 และมันจะเป็น Unicode
Bartosz Radaczyński

4
เพื่อให้ชัดเจนอย่างยิ่ง: เป็นความคิดที่ดีที่จะเปลี่ยนการเข้ารหัสเริ่มต้น นี่คล้ายกับการทำขาหักและเดินเหมือนว่าไม่มีอะไรเกิดขึ้นแทนที่จะให้หมอวางกระดูกให้เหมาะสม การจัดการโค้ดข้อความ Unicode ทั้งหมดควรทำอย่างสม่ำเสมอแทนที่จะอาศัยการเข้ารหัส / ถอดรหัสโดยนัย
Martijn Pieters

1

ประเภทที่เกี่ยวข้องกับคำตอบโดยเจเอฟเจบาสเตียน แต่ตรงกว่า

หากคุณมีปัญหานี้เมื่อพิมพ์ไปยังคอนโซล / เทอร์มินัลให้ทำสิ่งนี้:

>set PYTHONIOENCODING=UTF-8

3
set PYTHONIOENCODING=UTF-8อาจทำให้mojibakeหากคอนโซลใช้การเข้ารหัสที่แตกต่างกันเช่น cp437 มีประเด็นต่างๆcp65001 หากต้องการพิมพ์ Unicode ไปยังคอนโซล Windows ควรใช้ Unicode API ( WriteConsoleW()) ตามคำแนะนำของฉันซึ่งPYTHONIOENCODINGจะใช้เพื่อแทนที่อักขระที่ไม่สามารถแสดงในหน้ารหัส OEM ปัจจุบันด้วย?( WriteConsoleW()ใช้ได้แม้กับตัวอักษรดังกล่าว) PYTHONIOENCODINGสามารถใช้หากเอาต์พุตถูกเปลี่ยนเส้นทางไปยังไฟล์
jfs

1

Python 3.6 windows7: มีหลายวิธีในการเปิดตัว python คุณสามารถใช้คอนโซล python (ซึ่งมีโลโก้ python อยู่) หรือคอนโซล windows (มันเขียน cmd.exe ไว้)

ฉันไม่สามารถพิมพ์อักขระ utf8 ในคอนโซล windows ได้ การพิมพ์อักขระ 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 

หลังจากพยายามและไม่เข้าใจคำตอบข้างต้นฉันค้นพบว่ามันเป็นเพียงปัญหาการตั้งค่า คลิกขวาที่ด้านบนของหน้าต่างคอนโซล cmd บนแท็บfontเลือกคอนโซล lucida


0

James Sulak ถาม

มีวิธีใดบ้างที่ฉันสามารถทำให้ Python พิมพ์ a โดยอัตโนมัติได้? แทนที่จะล้มเหลวในสถานการณ์นี้?

โซลูชันอื่น ๆ แนะนำให้เราพยายามปรับเปลี่ยนสภาพแวดล้อม Windows หรือแทนที่print()ฟังก์ชั่นของ Python คำตอบด้านล่างนี้ใกล้เคียงกับคำขอของ Sulak มากขึ้น

ภายใต้ Windows 7 สามารถพิมพ์ Python 3.5 เพื่อพิมพ์ Unicode โดยไม่ต้องใช้ a UnicodeEncodeErrorดังนี้

    ในสถานที่ของ:     print(text)
    แทน:     print(str(text).encode('utf-8'))

แทนที่จะทิ้งข้อยกเว้นตอนนี้ Python จะแสดงอักขระ Unicode ที่ไม่สามารถพิมพ์ได้ รหัสเลขฐานสิบหก\ xNNเช่น:

  Halmalo n \ xe2 \ x80 \ x99 \ xc3 \ xa9tait บวก qu \ xe2 \ x80 \ x99un point noir

แทน

  Halmalo n'étaitบวก qu'un point noir

ที่ได้รับหลังเป็นที่นิยมparibus ceterisแต่อย่างอื่นในอดีตมีความถูกต้องสมบูรณ์สำหรับข้อความวินิจฉัย เนื่องจากมันแสดง Unicode ว่าเป็นค่าไบต์ที่แท้จริงซึ่งในอดีตอาจช่วยในการวินิจฉัยปัญหาการเข้ารหัส / ถอดรหัส

หมายเหตุ:str()จำเป็นต้องใช้การโทรด้านบนเพราะไม่เช่นนั้นencode()Python จะปฏิเสธอักขระ Unicode เป็น tuple ของตัวเลข

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.