Frage

Wenn die Ausgabe eines Python-Programm kochend, wird der Python-Interpreter über Codierung verwirrt und setzt es auf keine. Das bedeutet, ein Programm wie folgt aus:

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

wird gut funktionieren, wenn sie normal laufen, aber nicht mit:

  

UnicodeEncodeError: 'ASCII' codec Zeichen nicht codieren kann u '\ xa0' in Position 0: ordinal nicht im Bereich (128)

, wenn in einer Rohrfolge verwendet.

Was ist der beste Weg, um diese Arbeit zu machen, wenn Rohrleitungen? Kann ich sagen, dass es nur, was das Codieren der Shell / Dateisystem zu verwenden, / was auch immer verwendet wird?

Die Vorschläge, die ich bisher gesehen habe, sind Ihre site.py direkt zu ändern oder hartzucodieren die defaulten mit diesem Hack:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

Gibt es eine bessere Art und Weise Verrohrungsarbeiten zu machen?

War es hilfreich?

Lösung

Ihr Code funktioniert, wenn sie in einem Skript ausgeführt werden, da Python die Ausgabe an, was auch immer die Kodierung der Terminal-Anwendung codiert verwendet. Wenn Sie kochend kodieren müssen Sie es selbst.

Eine Faustregel: Immer Unicode verwenden intern. Dekodieren, was Sie bekommen, und kodieren, was Sie senden.

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

Ein weiteres didaktisches Beispiel ist ein Python-Programm zwischen ISO-8859-1 und UTF-8 zu konvertieren, alles zu machen Großbuchstaben dazwischen.

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)

das System Standard-Kodierung Einstellung ist eine schlechte Idee, da einige Module und Bibliotheken Sie können es ASCII ist auf die Tatsache nutzen verlassen. Tun Sie es nicht.

Andere Tipps

Zuerst bezüglich dieser Lösung:

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

Es ist nicht praktisch, explizit jedes Mal mit einer bestimmten Codierung zu drucken. Das wäre repetitiv und fehleranfällig ist.

Eine bessere Lösung ist zu ändern sys.stdout zu Beginn des Programms, mit einer ausgewählten Codierung zu codieren. Hier ist eine Lösung fand ich auf Python: Wie ist sys gewählt .stdout.encoding , insbesondere ein Kommentar von "Toka":

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

Sie möchten versuchen, die Umgebungsvariable „PYTHONIOENCODING“ auf „UTF_8“ zu ändern. Ich habe eine Seite auf meiner Tortur mit diesem Problem .

Tl; dr der Blog-Post:

gibt Ihnen

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻
export PYTHONIOENCODING=utf-8

die Arbeit tun, aber es kann nicht auf Python setzt sich ...

Was können wir tun, ist zu überprüfen, ob nicht setzen und dem Benutzer mitteilen, es zu setzen, bevor Anruf-Skript mit:

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 auf den Kommentar zu antworten: das Problem besteht nur, wenn auf stdout kochend. Getestet habe ich in Fedora 25 Python 2.7.13

python --version
Python 2.7.13

cat b.py

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

print sys.stdout.encoding

läuft ./b.py

UTF-8

läuft ./b.py | weniger

None

hatte ich einen ähnliches Problem letzte Woche . Es war leicht, in meiner IDE zu beheben (PyCharm).

Hier war mein fix:

Ab PyCharm Menüleiste: Datei -> Einstellungen ... -> Editor -> Datei Codierungen, dann setzen: "IDE Encoding", "Projekt-Encoding" und "Standardkodierung für Eigenschaften Dateien" ALL auf UTF-8 und sie arbeitet jetzt wie ein Zauber.

Hope, das hilft!

Eine vertretbare bereinigte Version von Craig McQueen Antwort.

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

Verbrauch:

with EncodedOut('utf-8'):
    print u'ÅÄÖåäö'

Ich kann „automatisieren“ es mit einem Aufruf an:

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

Ja, es ist möglich, eine Endlosschleife hier zu bekommen, wenn diese „setenv“ fehlschlägt.

Ich dachte nur, ich hier etwas erwähnen würde, die ich verbrachte eine lange Zeit mit experimentiert hatte, bevor ich endlich begriffen, was los war. Dies kann hier so für jeden offensichtlich sein, dass sie es nicht die Mühe gemacht haben, zu erwähnen. Aber es wäre mir geholfen haben, wenn sie haben, so auf diesem Prinzip ...!

NB: Ich Jython speziell bin mit, v 2.7, so dass nur möglicherweise kann dies nicht gelten CPython ...

NB2: die ersten beiden Zeilen meiner Py-Datei befinden sich hier:

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

Das „%“ (AKA „Interpolationsoperator“) string Konstruktion Mechanismus verursacht zusätzliche Probleme zu ... Wenn die Standard-Kodierung der „Umwelt“ ASCII ist und Sie versuchen, so etwas wie

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

Sie werden keine Schwierigkeiten haben, in Eclipse läuft ... In einer Windows-CLI (DOS-Fenster) Sie werden feststellen, dass die Codierung Code-Seite 850 (mein Windows 7 OS) oder etwas ähnliches, die europäische Zeichen mit Akzent zumindest umgehen kann, so dass es dann funktioniert.

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

wird auch funktionieren.

Wenn OTOH, Sie auf eine Datei aus dem CLI direkt, wird die stdout Codierung keine sein, die in ASCII-Standard wird (auf meinem O sowieso), die eine der oben genannten Abzüge nicht in der Lage zu handhaben ... (gefürchtete Codierungsfehler).

Also dann könnten Sie denken, dass Ihr stdout umzuleiten, indem Sie

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

und versucht, in der CLI-Rohrleitung in eine Datei ausgeführt ... Sehr seltsam, drucken A oben arbeiten ... Aber Druck B oben wird die Codierung Fehler werfen! Im Folgenden wird jedoch OK arbeiten:

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

Die Schlussfolgerung, die ich gekommen, um (vorläufig) ist, dass, wenn eine Zeichenkette, die angegeben wird, ein Unicode sein string mit dem „u“ Präfix in das Verzeichnis% -Handhabung Mechanismus vorgelegt wird es die Verwendung der Standardumgebung Codierung einzubinden erscheint, , unabhängig davon, ob Sie stdout gesetzt haben zu umleiten!

Wie die Menschen damit umgehen ist eine Frage der Wahl. Ich würde eine Unicode-Experten begrüßen zu sagen, warum dies geschieht, ob ich es in irgendeiner Weise falsch verstanden haben, was die bevorzugte Lösung für dieses Problem, ob es gilt auch für CPython , ob es in Python geschieht 3 etc., etc.

Unter Ubuntu 12.10 und GNOME-Terminal, kein Fehler erzeugt wird, wenn das Programm druckt auf stdout oder an ein Rohr für andere Programme angeschlossen. Beide Dateicodierung und Terminal-Codierung ist UTF-8 .

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

Was O und Terminal-Emulator verwenden Sie? Ich habe gehört, einige meiner Kollegen haben ähnliche Probleme bei der Verwendung von iTerm 2 und OS X; iTerm 2 kann die Ursache sein.

Update: Diese Antwort falsch ist - siehe Kommentare für Details

Ich lief in dieses Problem in einer Legacy-Anwendung, und es war schwierig, zu erkennen, wo, was gedruckt wurde. Ich half mir mit diesem Hack:

# 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)

Auf meinem Skript, test.py:

import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)

Beachten Sie, dass dies alles drucken ändert ruft eine Codierung zu verwenden, so dass Sie Ihre Konsole druckt diese:

$ python test.py
b'Axwell \xce\x9b Ingrosso'
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top