Python, Unicode i konsola Windows

Kiedy próbuję wydrukować ciąg znaków Unicode w konsoli Windows, pojawia się błąd UnicodeEncodeError: 'charmap' codec can't encode character ..... Zakładam, że jest tak dlatego, że konsola Windows nie akceptuje znaków Tylko Unicode. Jaki jest najlepszy sposób na obejście tego? Czy jest jakiś sposób, aby Python automatycznie wydrukował ? zamiast zawieść w tej sytuacji?

Edit: używam Pythona 2.5.


Uwaga: @ LasseV.Odpowiedź karlsena ze znacznikiem jest trochę nieaktualna (od 2008 roku). Proszę skorzystać z rozwiązania/odpowiedzi / sugestie poniżej ostrożnie!!

@odpowiedź JFSebastian jest bardziej aktualna na dzień dzisiejszy (6 stycznia 2016).

Author: Community, 2008-08-08

13 answers

Uwaga: ta odpowiedź jest trochę nieaktualna (od 2008 roku). Skorzystaj z poniższego rozwiązania ostrożnie!!


Oto strona opisująca problem i rozwiązanie (Szukaj na stronie tekstu Wrapping sys.stdout do instancji):

PrintFails-Python Wiki

Oto fragment kodu z tej strony:

$ 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
  Б
  Б

Jest trochę więcej informacji na tej stronie, warto przeczytać.

 32
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-04 17:18:53

Aktualizacja: Python 3.6 implementuje PEP 528: Zmień kodowanie konsoli Windows na UTF-8: domyślna konsola w systemie Windows będzie teraz akceptować wszystkie znaki Unicode. wewnętrznie używa tego samego API Unicode co pakiet win-unicode-console wymieniony poniżej . Powinno zadziałać.


Dostaję UnicodeEncodeError: 'charmap' codec can't encode character... błąd.

Błąd oznacza, że znaki Unicode, które próbujesz wydrukować, nie mogą być reprezentowane za pomocą current (chcp) kodowanie znaków konsoli. Kodowanie jest często kodowaniem 8-bitowym, takim jak cp437, które może reprezentować tylko ~0x100 znaków z ~1M znaków Unicode:

>>> u"\N{EURO SIGN}".encode('cp437')
Traceback (most recent call last):
...
UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 0:
character maps to 

Zakładam, że jest tak dlatego, że konsola Windows nie akceptuje znaków Tylko Unicode. Jaki jest najlepszy sposób na obejście tego?

Konsola Windows akceptuje znaki Unicode i może je nawet wyświetlać (tylko BMP) Jeśli odpowiednia czcionka jest skonfigurowana . WriteConsoleW() API powinno być używane zgodnie z sugestią w @Daira Hopwood ' s answer . Można go nazwać transparentnie, tzn. nie musisz i nie powinieneś modyfikować swoich skryptów, jeśli używasz win-unicode-console Pakiet:

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

Zobacz o co chodzi z Pythonem 3.4, Unicode, różnymi językami i Windows?

Czy Jest jakiś sposób, żebym mógł zrobić Pythona automatycznie wydrukować ? zamiast niepowodzenia w tej sytuacji?

Jeśli wystarczy zastąpić wszystkie nieenkodowalne znaki z ? w Twoim przypadku możesz ustawić PYTHONIOENCODING envvar :

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

W Pythonie 3.6+ kodowanie określone przez PYTHONIOENCODING envvar jest ignorowane dla interaktywnych buforów konsoli, chyba że envvar jest ustawiony na niepusty łańcuch znaków.

 53
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44

Pomimo innych wiarygodnie brzmiących odpowiedzi sugerujących zmianę strony kodowej na 65001, nie działa . (Również zmiana domyślnego kodowania za pomocą sys.setdefaultencoding to nie jest dobrym pomysłem .)

Zobacz to pytanie Po szczegóły i kod, który działa.

 25
Author: Daira Hopwood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33

Jeśli nie jesteś zainteresowany uzyskaniem wiarygodnej reprezentacji złych znaków, możesz użyć czegoś takiego (pracując z Pythonem > = 2.6, w tym 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}")

Złe znaki w łańcuchu zostaną przekonwertowane w reprezentację, która jest drukowana przez konsolę Windows.

 14
Author: Giampaolo Rodolà,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-19 18:48:28

Poniższy kod sprawi, że Python będzie wyświetlany na konsoli jako UTF-8 nawet w systemie Windows.

Konsola wyświetli znaki dobrze na Windows 7, ale na Windows XP nie wyświetli ich dobrze, ale przynajmniej będzie działać i co najważniejsze będziesz miał spójne wyjście ze Skryptu na wszystkich platformach. Będziesz mógł przekierować wyjście do pliku.

Poniższy kod został przetestowany z Pythonem 2.6 na 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"
 10
Author: sorin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-12 20:45:44

Jak odpowiedź Giampaolo Rodolà, ale jeszcze bardziej brudne: naprawdę, naprawdę zamierzam spędzić dużo czasu (wkrótce) zrozumienie całego tematu kodowania i jak mają one zastosowanie do konsoli Windoze,

Na razie chciałem tylko sthg, co oznaczałoby, że mój program nie ulegnie awarii, i co zrozumiałem ... a także co nie wymagało importowania zbyt wielu egzotycznych modułów (w szczególności używam Jythona, więc połowa czasu moduł Pythona okazuje się nie być dostępne).

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

NB "pr" jest krótszy do wpisania niż "print" (i nieco krótszy do wpisania niż "safeprint")...!

 3
Author: mike rodent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-09 22:14:15

Dla Pythona 2 Spróbuj:

print unicode(string, 'unicode-escape')

Dla Pythona 3 Spróbuj:

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

Lub spróbuj win-unicode-console:

pip install win-unicode-console
py -mrun your_script.py
 3
Author: shubaly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 05:07:50

Przyczyną twojego problemu jest A NIE konsola Win nie chce akceptować Unicode (jak to robi, bo Domyślam się, że Win2k). Jest to domyślne kodowanie systemowe. Wypróbuj ten kod i zobacz co ci daje:

import sys
sys.getdefaultencoding()

Jeśli jest napisane ascii, jest twoja przyczyna ;-) Musisz utworzyć plik o nazwie sitecustomize.py i umieścić go pod Path Pythona (ja umieścić go pod /usr / lib / python2.5 / site-packages, ale to jest differen na Win-jest c:\python\lib\site-packages czy coś), z następująca treść:

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

I być może zechcesz również określić kodowanie w swoich plikach:

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

Edit: więcej informacji można znaleźć W excellent the Dive into Python book

 2
Author: Bartosz Radaczyński,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 01:52:54

Podobne do odpowiedzi J. F. Sebastiana, ale bardziej bezpośrednie.

Jeśli masz ten problem podczas drukowania na konsoli / terminalu, zrób to:

>set PYTHONIOENCODING=UTF-8
 1
Author: Kinjal Dixit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 07:53:43

Python 3.6 windows7: istnieje kilka sposobów na uruchomienie Pythona możesz użyć konsoli Pythona (która ma logo Pythona na nim) lub konsoli windows (jest napisane cmd.exe na nim).

Nie mogłem wydrukować znaków utf8 w konsoli windows. Drukowanie znaków utf-8 powoduje ten błąd:

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 

Po próbie i nie zrozumieniu powyższej odpowiedzi odkryłem, że to tylko problem z ustawieniem. Kliknij prawym przyciskiem myszy na górze okna konsoli cmd, na karcie font Wybierz konsola lucida.

 1
Author: J. Does,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 20:08:34

TL; DR:

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

Sam na to wpadłem, pracując nad botem Twitch chat (IRC). (Python 2.7 latest)

Chciałem przeanalizować wiadomości czatu, aby odpowiedzieć...

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

Ale również wydrukować je bezpiecznie do konsoli w formacie czytelnym dla człowieka:

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

Poprawiło to problem z wyrzucaniem błędów bota UnicodeEncodeError: 'charmap' i zastąpiło znaki unicode znakiem ?.

 1
Author: Matthew Estock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-01 15:52:05

Jakub Sulak zapytał,

Czy Jest jakiś sposób, aby Python automatycznie wydrukował a ? zamiast porażki w tej sytuacji?

Inne rozwiązania zalecają próbę modyfikacji środowiska Windows lub zastąpienia funkcji print() Pythona. Odpowiedź poniżej przybliża się do spełnienia prośby Sulaka.

Pod Windows 7, Python 3.5 może być wykonany do drukowania Unicode bez rzucania UnicodeEncodeError w następujący sposób:

W miejsce:    print(text)
    substytut:     print(str(text).encode('utf-8'))

Zamiast rzucać wyjątek, Python wyświetla teraz niedrukowalne znaki Unicode jako \XNN kody szesnastkowe, np.:

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

Zamiast

Halmalo n 'était plus qu' un point noir

To drugie jest preferowane ceteris paribus , ale poza tym pierwsze jest całkowicie dokładne dla komunikatów diagnostycznych. Ponieważ wyświetla Unicode jako literalne wartości bajtów te pierwsze mogą również pomóc w diagnozowaniu problemów z kodowaniem/dekodowaniem.

Uwaga: powyższe wywołanie str() jest potrzebne, ponieważ w przeciwnym razie encode() powoduje, że Python odrzuca znak Unicode jako krotkę liczb.

 0
Author: CODE-REaD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 16:19:05

Po prostu wpisz ten kod w wierszu poleceń przed wykonaniem skryptu Pythona:

chcp 65001 & set PYTHONIOENCODING=utf-8
 0
Author: c97,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 22:11:03