Verwenden von utf-8 Eingabe für cmd Python Modul

Bei der Erstellung einer kleinen CLI Notebook-Anwendung habe ich mich entschlossen, mit der cmd Python-Bibliothek zu gehen (siehe auch cmd auf PyMOTW).

Meine Schale ist UTF-8.

 → echo $LANG fr_FR.utf-8 → echo $LC_ALL fr_FR.utf-8 

Und es funktioniert ganz gut

 → echo "東京"東京 

Starten Sie den Code meiner kleinen App und versuchen, utf-8 zu verwenden:

 → python nb.py log> foobar 2013-01-15 foobar log> æ±äº¬ 2013-01-15 æ±äº¬ 

Bearbeitet Der erwartete Eingang / Ausgang ist. Wenn ich utf-8 Zeichen, Akzent oder japanische Zeichen in diesem Fall, bekomme ich Müll.

 log> 東京2013-01-15 東京 

Wenn also das Programm gestartet wird, ändert die Befehlszeile den Typ der Eingabe.

 #!/usr/bin/env python2.7 # encoding: utf-8 import datetime import os.path import logging import cmd ROOT = "~/test/" NOTENAME = "notes.md" def todaynotepath(rootpath, notename): isodate = datetime.date.today().isoformat() isodate.replace("-", "/") return rootpath + isodate.replace("-", "/") + "/%s" % (notename) def addcontent(content): logging.info(content) class NoteBook(cmd.Cmd): """Simple cli notebook.""" prompt = "log> " def precmd(self, line): # What is the date path NOW notepath = todaynotepath(ROOT, NOTENAME) # if the directory of the note doesn't exist, create it. notedir = os.path.dirname(notepath) if not os.path.exists(notedir): os.makedirs(notedir) # if the file for notes today doesn't exist, create it. logging.basicConfig(filename=notepath, level=logging.INFO, format='%(asctime)s - %(message)s') return cmd.Cmd.precmd(self, line) def default(self, line): if line: print datetime.date.today().isoformat(), line addcontent(line) def do_EOF(self, line): return True def postloop(self): print if __name__ == "__main__": NoteBook().cmdloop() 

Also ich denke, es könnte Dinge geben, um in der ursprünglichen Klasse von cmd zu überschreiben. Ich überprüfte das Modul aber ohne Glück noch.

Bearbeiten 2: LESSCHARSET wie von @dda empfohlen

 LANG=fr_FR.utf-8 LANGUAGE=fr_FR.utf-8 LC_ALL=fr_FR.utf-8 LC_CTYPE=fr_FR.UTF-8 LESSCHARSET=utf-8 

2 Solutions collect form web for “Verwenden von utf-8 Eingabe für cmd Python Modul”

Dein Code funktioniert perfekt für mich, Karl. Sieh dir das an:

 dda$ ./nb.py log> tagada 2013-01-15 tagada log> 香港2013-01-15 香港log> 

Und die notes.md Datei enthält die richtigen Einträge. Also ich glaube nicht, dass es cmd , das ist hier schuld, aber wahrscheinlich etwas in deinen Terminal-Einstellungen. Versuchen Sie Hinzufügen

 export LESSCHARSET=utf-8 

In deinem .profile .

Ich dachte, es gäbe eine andere Frage wie diese auf SO, aber speziell für ein C-Bibliothek-Modul; Diese Antwort kann dort eher passend gewesen sein, aber ich kann den Link jetzt nicht finden :)

Kurz locale.setlocale(locale.LC_ALL, '') , meine Antwort wäre – versuchen locale.setlocale(locale.LC_ALL, '') bevor Sie das Modul laden (ich habe mir noch nicht cmd verwendet). Ausführlicher:

Ich habe versucht, die SWIG Python Bindungen für Subversion (SVN) zu verwenden. Dies sind grundsätzlich eine automatische Schnittstelle für Python von SWIG, direkt aus SVN C Bibliothek Code ( libsvn1 ) produziert. Wenn ich den svn status MyWorkingCopy aus dem Terminal svn status MyWorkingCopy , hängt es in den libsvn Code – und es ist seit Jahren nicht mehr libsvn (für dieses Repository). Aber, als ich das Python-Beispiel lief (das Gleiche wie svn status ) – das hängt in den gleichen libsvn Code – vom selben Terminal, dann würde ich einen UTF-8 verwandten Fehler von libsvn / SWIG bekommen, was abstürzen würde Mein Python-Skript.

Das bedeutet, dass Python irgendwie die Bibliothek "beeinflusst" hat, um sich in Bezug auf Zeichensätze anders zu verhalten. Aber mein Terminal berichtet:

 $ locale LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_CTYPE="en_US.UTF-8" ... LC_IDENTIFICATION="en_US.UTF-8" LC_ALL= 

Also, es geht nicht darum, was das Terminal / Shell ( bash in diesem Fall) denke – es geht darum, was der zugrunde liegende C-Code (von libsvn in diesem Fall) über aktuelle Einstellungen denkt. Und das gleiche, dachte ich, gilt für python:

 $ python -c 'import locale; print locale.getdefaultlocale()' ('en_US', 'UTF-8') 

Also, jetzt ist es zu sehen, was C-Code sieht, wenn lief von Terminal vs, wenn lief von Python (in der gleichen Terminal). Debugging libsvn weiter, es stellte sich heraus, es kommt eigentlich aus einer anderen Bibliothek, libapr (Apache Portable Runtime), die SVN für die Speicherzuweisung verwendet. Was ich am Ende tat, schreibt eine Wiederholung der Zeichenfolge Kopieren von libsvn die libapr in einem eigenständigen C-Programm verwendet; Und baute es dann über SWIG als Python-Modul. Dieses Programm, aprtest , akzeptiert einen String als Argument, ruft die libapr Engine auf, um sie zu kopieren und zeigt das Ergebnis an. Die Quelle dafür ist hier:

Siehe das Skript build-aprtest.sh für Bibliotheksversionen, mit denen ich gearbeitet habe (Ubuntu 11.04); Zu bauen, laufen bash build-aprtest.sh .

Nun, wenn du die ausführbare Datei in Terminal gebaut hast, bekommst du:

 $ locale LANG=en_US.UTF-8 ... $ ./aprtest "test" LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 0 (*dest)->data: test $ ./aprtest "test東京" LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 22 

Der libapr Motor ist bei der UTF-8-Eingabe von der Kommandozeile trotz der Terminal-Meldung UTF-8 eindeutig auf UTF-8 eingegeben. Und wenn wir als gemeinsames Modul (genannt aprtest_s ) durch Python laufen:

 $ python -c 'import aprtest_s; aprtest_s.pysmain("test")' LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 0 (*dest)->data: test $ python -c 'import aprtest_s; aprtest_s.pysmain("test東京")' LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 22 

… das gleiche passiert ( btw, für das gleiche Problem mit SVN und APR, aber für Perl, siehe Gibt es eine Variable oder Funktion, die die native Plattform-Codierung (APR_LOCALE_CHARSET) zurückgibt ). So können wir folgern:

  • Es spielt keine Rolle, ob das C-Programm direkt vom Terminal geleitet wird, oder über Python – das C-Programm sieht einfach eine andere Locale / Codierung Einstellungen, von dem, was das aufrufende Programm sehen kann
  • Es gibt kein Problem mit ASCII-Strings, nur die UTF-8

Also, wie dann funktioniert der svn-Client ordnungsgemäß vom Terminal, während letztlich mit libapr ohne Absturz? Nun, wie man es sehen kann, sind die Kommentare der Quelle für aprtest_s.c ; Es ist durch das Setzen des eigenen Gebietsschemas des Programms, indem Sie die C-Funktion setlocale(LC_CTYPE,"") , die, wie sich herausstellt, alle Kategorien des Gebietsschemas des Prozesses setzt . Dieses Problem ist eigentlich in apr-dev Mailing-Liste erwähnt: Re: Misbehavior von apr_os_locale_encoding unter Windows :

… diese Kommissionierung eines der 55 verschiedenen aktuellen Locales kann wohl nur von der Anwendung richtig gemacht werden, nicht von APR.

Also, indem setlocale() in der C-Applikation libapr , libapr ausdrücklich das Default-Locale explizit aus, also libapr weiß es. Im Testfall muss dieser Aufruf zum setlocale vor einem Aufruf von apr_xlate_open .

Nun, die gebuchte Version von aprtest macht nicht setlocale , also können wir sehen, was von Python geschieht (beachten Sie auch diese ), wenn wir die Python-Version verwenden, locale.setlocale() :

 $ PYTHONIOENCODING='utf-8' echo 'import sys;print sys.stdin.encoding' | python None $ echo 'import sys;print sys.stdin.encoding' | PYTHONIOENCODING='utf-8' python utf-8 $ locale LANG=en_US.UTF-8 LANGUAGE=en_US:en ... $ python Python 2.7.1+ (r271:86832, Sep 27 2012, 21:16:52) [GCC 4.5.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import aprtest_s >>> aprtest_s.print_locale() LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 >>> aprtest_s.pysmain("test") LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 0 (*dest)->data: test >>> aprtest_s.pysmain("test東京") LC_CTYPE 0 CODESET 14 ANSI_X3.4-1968 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 22 >>> import locale >>> print locale.getdefaultlocale() ('en_US', 'UTF-8') >>> print locale.getlocale() (None, None) >>> import sys >>> print sys.stdin.encoding UTF-8 >>> locale.setlocale(locale.LC_ALL, '') 'en_US.UTF-8' >>> print sys.stdin.encoding UTF-8 >>> print locale.getlocale() ('en_US', 'UTF-8') >>> aprtest_s.pysmain("test") LC_CTYPE 0 CODESET 14 UTF-8 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 0 (*dest)->data: test >>> aprtest_s.pysmain("test東京") LC_CTYPE 0 CODESET 14 UTF-8 apr_xlate_open: apr_err=0 apr_xlate_conv_buffer apr_err == 0 (*dest)->data: test東京>>> 

Also, um sicherzustellen, was ist es, dass eine C-Anwendung sieht in Python – verwenden locale.getlocale() ( NOT locale.getdefaultlocale() ). So wie ich es jetzt verstehe, gibt getdefaultlocale einige OS / User-Einstellungen zurück, die irgendwo gespeichert werden, die als Standard gelten, aber unbedingt als Standard angewendet werden, wenn eine Anwendung gestartet wird. Und getlocale bekommt die aktuellen, aktuell angewandten Locale-Einstellungen. Und ich denke, wenn wir setlocale mit leerem String aufrufen, verursacht der Rest des Codes: die Standardeinstellungen (die von getdefaultlocale ) zu lesen und dann die Standardeinstellungen als aktuell anzuwenden.

Und als endgültige Note – auch wenn es aussieht, die Codierungseinstellungen von stdin / stdout (scheinbar) haben nichts mit der Verschlüsselung des aktuellen Gebietsschemas zu tun (zumindest gesehen von einem C-Programm, das in dieser Umgebung läuft).

Hoffe das hilft jemandem,
Prost!

  • Kodierung auf PostgreSQL, Python, Jinja2
  • SyntaxError: Nicht-UTF-8-Code beginnend mit '\ x91'
  • Python os.walk Machen Sie es Unterstützung Unicode / UTF-8?
  • UTF8-Stiche im Ubuntu-Terminal mit einem Python-Skript anzeigen
  • Machen Sie Emacs verwenden UTF-8 mit Python Interactive Mode
  • Warum erkennt Python meine utf-8-codierte Quelldatei nicht?
  • Python 2.7 Zeichen \ u2013 [duplizieren]
  • UnicodeEncodeError: 'ascii' Codec kann Zeichen nicht in Position 0-5 codieren: ordinal nicht im Bereich (128) [duplizieren]
  • Python-Datei Eingabe String: wie zu behandeln Escaped Unicode-Zeichen?
  • Drucken von UTF-8 in Python 3 mit Sublime Text 3
  • Python + PostgreSQL + merkwürdiger Ascii = UTF8-Codierungsfehler
  • Python ist die beste Programmiersprache der Welt.