Ustawianie poprawnego kodowania podczas przesyłania stdout w Pythonie

Podczas przesyłania wyjścia programu Pythona, interpreter Pythona jest zdezorientowany co do kodowania i ustawia go na None. Oznacza to taki program:

# -*- coding: utf-8 -*-
print u"åäö"

Będzie działać poprawnie, gdy zostanie uruchomiony normalnie, ale nie z:

UnicodeEncodeError: 'ASCII' kodek nie może zakodować znaku u '\xa0 ' W POZYCJI 0: porządkowy nie w zakresie (128)

W przypadku użycia w sekwencji rur.

Jaki jest najlepszy sposób, aby to działało podczas orurowania? Czy mogę mu powiedzieć, żeby używał czegokolwiek kodowanie powłoki / systemu plików / czego używa?

Sugestie, które do tej pory widziałem, to zmodyfikowanie twojego site.py bezpośrednio lub hardcoding domyślnego kodowania za pomocą tego hacka:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"
Czy istnieje lepszy sposób na wykonanie orurowania?
Author: Peter Mortensen, 2009-01-29

10 answers

Twój kod działa, gdy jest uruchamiany w skrypcie, ponieważ Python koduje wyjście do dowolnego kodowania używanego przez Twoją aplikację terminalową. Jeśli używasz orurowania, musisz to zakodować samodzielnie.

Regułą jest: Zawsze używaj Unicode wewnętrznie. Odszyfruj to, co otrzymujesz i Zakoduj to, co wysyłasz.

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

Innym dydaktycznym przykładem jest program Pythona do konwersji pomiędzy ISO-8859-1 i UTF-8, dzięki czemu wszystko pomiędzy nimi jest pisane wielkimi literami.

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

Ustawienie domyślnego kodowania systemu to zły pomysł, ponieważ niektóre moduły i biblioteki, których używasz, mogą polegać na tym, że jest to ASCII. Nie rób tego.

 145
Author: nosklo,
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
2014-11-11 18:30:18

Po pierwsze, odnośnie tego rozwiązania:

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

Jawne drukowanie z danym kodowaniem za każdym razem jest niepraktyczne. To byłoby powtarzalne i podatne na błędy.

Lepszym rozwiązaniem jest zmiana sys.stdout na początku programu, aby zakodować za pomocą wybranego kodowania. Oto jedno rozwiązanie, które znalazłem na Pythonie: jak jest sys.stdout.kodowanie wybrane?, w szczególności komentarz "toka":

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
 160
Author: Craig McQueen,
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
2009-07-23 02:49:37

Możesz spróbować zmienić zmienną środowiskową "PYTHONIOENCODING" na " utf_8."Napisałem stronę O mojej Gehennie z tym problemem .

Tl;dr Z wpisu na blogu:

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))

Daje

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
 115
Author: daveagp,
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-10-05 01:02:49
export PYTHONIOENCODING=utf-8

Wykonaj zadanie, ale nie możesz ustawić go na samym Pythonie ...

To co możemy zrobić to zweryfikować czy nie jest ustawione i powiedzieć użytkownikowi aby ustawił je przed wywołaniem skryptu za pomocą:

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)

Update to reply to the comment: problem po prostu istnieje podczas orurowania na stdout . Testowałem w Fedorze 25 Python 2.7.13

python --version
Python 2.7.13

Kot b.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys

print sys.stdout.encoding

Bieganie ./b.py

UTF-8

Bieganie ./b.py / less

None
 51
Author: Sérgio,
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-20 15:58:26

Miałem podobny problem w zeszłym tygodniu . To było łatwe do naprawienia w moim IDE (PyCharm).

Oto moja poprawka:

Począwszy od paska menu PyCharm: Plik - > Ustawienia... - >Edytor - > kodowanie plików, następnie Ustaw: "kodowanie IDE", "kodowanie projektu" i "domyślne kodowanie dla plików właściwości" wszystko do UTF-8 i teraz działa jak urok.

Mam nadzieję, że to pomoże!

 5
Author: CLaFarge,
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-06-21 02:54:18

Dyskusyjna Wersja odpowiedzi Craiga McQueena.

import sys, codecs
class EncodedOut:
    def __init__(self, enc):
        self.enc = enc
        self.stdout = sys.stdout
    def __enter__(self):
        if sys.stdout.encoding is None:
            w = codecs.getwriter(self.enc)
            sys.stdout = w(sys.stdout)
    def __exit__(self, exc_ty, exc_val, tb):
        sys.stdout = self.stdout

Użycie:

with EncodedOut('utf-8'):
    print u'ÅÄÖåäö'
 3
Author: Tompa,
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-04-13 10:24:12

Mógłbym "zautomatyzować" to wywołaniem do:

def __fix_io_encoding(last_resort_default='UTF-8'):
  import sys
  if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
      import os
      defEnc = None
      if defEnc is None :
        try:
          import locale
          defEnc = locale.getpreferredencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.getfilesystemencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.stdin.encoding
        except: pass
      if defEnc is None :
        defEnc = last_resort_default
      os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
      os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding

Tak, możliwe jest uzyskanie nieskończonej pętli, jeśli ten "setenv" zawiedzie.

 2
Author: jno,
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-03-15 10:08:10

Pomyślałem, że wspomnę o czymś, z czym musiałem długo eksperymentować, zanim w końcu zdałem sobie sprawę, co się dzieje. To może być tak oczywiste dla wszystkich tutaj, że nie pofatygowali się wspomnieć o tym. Ale pomogłoby mi, gdyby tak było, więc na tej zasadzie...!

NB: używam Jython w szczególności v 2.7, więc prawdopodobnie może to nie dotyczyć CPython...

NB2: pierwsze dwie linijki mojego pliku. py tutaj są:

# -*- coding: utf-8 -*-
from __future__ import print_function

Mechanizm konstrukcji łańcuchów " % "(AKA" operator interpolacji") powoduje również dodatkowe problemy... Jeśli domyślnym kodowaniem "environment" jest ASCII i próbujesz zrobić coś w stylu

print( "bonjour, %s" % "fréd" )  # Call this "print A"

Nie będziesz miał trudności z uruchomieniem w Eclipse... W Windows CLI (DOS window) znajdziesz, że kodowanie to strona kodowa 850 (mój system operacyjny Windows 7) lub coś podobnego, które może obsługiwać Europejskie znaki akcentowane przynajmniej, więc będzie praca.

print( u"bonjour, %s" % "fréd" ) # Call this "print B"

Będzie również działać.

Jeśli, OTOH, skierujesz Plik z CLI, kodowanie stdout będzie None, które domyślnie będzie ASCII (w moim systemie operacyjnym), które nie będzie w stanie obsłużyć żadnego z powyższych wydruków... (bał błąd kodowania).

Więc możesz pomyśleć o przekierowaniu swojego stdout za pomocą

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

I spróbuj uruchomić w CLI rurociągu do pliku... Bardzo dziwne, Wydruk powyżej zadziała... Ale Wydruk B powyżej spowoduje błąd kodowania! Na następujące będą jednak działać OK:

print( u"bonjour, " + "fréd" ) # Call this "print C"

Wniosek, do którego doszedłem (tymczasowo) jest taki, że jeśli ciąg znaków, który jest określony jako Unicode ciąg znaków z przedrostkiem "u" jest przesyłany do mechanizmu obsługi%, wydaje się, że wiąże się z użyciem domyślnego kodowania środowiska, niezależnie od tego, czy Ustawiłeś stdout na redirect!

To, jak ludzie sobie z tym radzą, jest kwestią wyboru. Zapraszam eksperta Unicode do powiedzenia dlaczego tak się dzieje, czy mam pomyliłem się w jakiś sposób, jakie jest preferowane rozwiązanie tego problemu, czy dotyczy to również CPython , czy dzieje się to w Pythonie 3 itp., itd.
 1
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
2014-11-11 18:44:16

W Ubuntu 12.10 i terminalu GNOME nie występuje błąd, gdy program drukuje na stdout lub podłącza się do rury dla innych programów. Zarówno kodowanie plików, jak i kodowanie terminali to UTF-8 .

$ cat a.py
# -*- coding: utf-8 -*-
print "åäö"
$ python a.py
åäö
$ python a.py | tee out
åäö

Jakiego systemu operacyjnego i emulatora terminala używasz? Słyszałem, że niektórzy z moich kolegów mają podobne problemy podczas korzystania z iTerm 2 i OS X; iTerm 2 może być winowajcą.

Update: ta odpowiedź jest błędna - Zobacz komentarze szczegóły

 0
Author: fossilet,
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-03-04 15:38:58

Napotkałem ten problem w starszej aplikacji i trudno było określić, gdzie Wydrukowano to, co zostało wydrukowane. Pomogłem sobie z tym hackiem:

# encoding_utf8.py
import codecs
import builtins


def print_utf8(text, **kwargs):
    print(str(text).encode('utf-8'), **kwargs)


def print_utf8(fn):
    def print_fn(*args, **kwargs):
        return fn(str(*args).encode('utf-8'), **kwargs)
    return print_fn


builtins.print = print_utf8(print)
/ Align = "left" / test.py:
import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)

Zauważ, że to zmienia wszystkie wywołania do drukowania, aby używać kodowania, więc konsola wydrukuje to:

$ python test.py
b'Axwell \xce\x9b Ingrosso'
 0
Author: cessor,
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-02-22 12:55:56