PEP 100 – Python Unicode Integration
- Autor:
- Marc-André Lemburg <mal at lemburg.com>
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 10-Mär-2000
- Python-Version:
- 2.0
- Post-History:
Inhaltsverzeichnis
- Historischer Hinweis
- Einleitung
- Konventionen
- Allgemeine Anmerkungen
- Unicode Standard-Codierung
- Unicode Konstruktoren
- Unicode Typobjekt
- Unicode Ausgabe
- Unicode Ordnungszahlen
- Vergleich & Hash-Wert
- Konvertierung (Coercion)
- Ausnahmen
- Codec (Coder/Decoder) Lookup
- Standard Codecs
- Codec Schnittstellendefinition
- Leerzeichen
- Groß-/Kleinschreibung
- Zeilenumbrüche
- Unicode Zeicheneigenschaften
- Private Code Point Bereiche
- Internes Format
- Puffer-Schnittstelle
- Pickle/Marshalling
- Reguläre Ausdrücke
- Formatierungsmarker
- Internes Argument Parsen
- Datei/Stream Ausgabe
- Datei/Stream Eingabe
- Unicode Methoden & Attribute
- Code Basis
- Testfälle
- Referenzen
- Geschichte dieses Vorschlags
Historischer Hinweis
Dieses Dokument wurde ursprünglich von Marc-Andre in den Pre-PEP-Tagen geschrieben und wurde bis einschließlich Python 2.1 als Misc/unicode.txt in Python-Distributionen verteilt. Die letzte Überarbeitung des Vorschlags an diesem Ort trug die Versionsnummer 1.7 (CVS-Revision 3.10). Da das Dokument offensichtlich den Zweck eines informativen PEPs im Post-PEP-Zeitalter erfüllt, wurde es hierher verschoben und im Einklang mit den PEP-Richtlinien neu formatiert. Zukünftige Überarbeitungen werden an diesem Dokument vorgenommen, während Misc/unicode.txt einen Verweis auf diesen PEP enthalten wird.
-Barry Warsaw, PEP-Editor
Einleitung
Die Idee dieses Vorschlags ist es, native Unicode 3.0 Unterstützung zu Python hinzuzufügen, auf eine Weise, die Unicode-Strings so einfach wie möglich nutzbar macht, ohne dabei zu viele Fallstricke zu erzeugen.
Da dieses Ziel nicht einfach zu erreichen ist – Strings gehören zu den fundamentalsten Objekten in Python – erwarten wir, dass dieser Vorschlag einige signifikante Verfeinerungen erfahren wird.
Beachten Sie, dass die aktuelle Version dieses Vorschlags aufgrund der vielen verschiedenen Aspekte der Unicode-Python-Integration noch etwas unsortiert ist.
Die neueste Version dieses Dokuments ist immer verfügbar unter: http://starship.python.net/~lemburg/unicode-proposal.txt
Ältere Versionen sind verfügbar als: http://starship.python.net/~lemburg/unicode-proposal-X.X.txt
[ed. Anm.: Neue Überarbeitungen sollten an diesem PEP-Dokument vorgenommen werden, während die historische Aufzeichnung vor Version 1.7 aus der URL von MAL oder Misc/unicode.txt abgerufen werden sollte.]
Konventionen
- In Beispielen verwenden wir u = Unicode-Objekt und s = Python-String
- Markierungen mit ‘XXX’ zeigen Diskussionspunkte (PODs) an
Allgemeine Anmerkungen
- Unicode-Codierungsnamen sollten bei der Ausgabe klein geschrieben und bei der Eingabe nicht case-sensitiv sein (sie werden von allen APIs, die einen Codierungsnamen als Eingabe nehmen, in Kleinbuchstaben umgewandelt).
- Codierungsnamen sollten den Namenskonventionen des Unicode Consortiums folgen: Leerzeichen werden durch Bindestriche ersetzt, z.B. ‘utf 16’ wird als ‘utf-16’ geschrieben.
- Codec-Module sollten die gleichen Namen verwenden, aber mit durch Unterstriche ersetzten Bindestrichen, z.B.
utf_8,utf_16,iso_8859_1.
Unicode Standard-Codierung
Die Unicode-Implementierung muss einige Annahmen über die Codierung von 8-Bit-Strings treffen, die ihr zur Konvertierung übergeben werden, und über die Standardcodierung für die Konvertierung von Unicode in Strings, wenn keine spezifische Codierung angegeben wird. Diese Codierung wird in diesem Text als <Standardcodierung> bezeichnet.
Dafür verwaltet die Implementierung eine globale Variable, die im `site.py` Python-Startskript gesetzt werden kann. Nachfolgende Änderungen sind nicht möglich. Die <Standardcodierung> kann über die beiden `sys`-Modul-APIs gesetzt und abgefragt werden:
sys.setdefaultencoding(encoding)- Setzt die <Standardcodierung>, die von der Unicode-Implementierung verwendet wird. `encoding` muss eine Codierung sein, die von der Python-Installation unterstützt wird, andernfalls wird ein `LookupError` ausgelöst.
Hinweis: Diese API ist nur in `site.py` verfügbar! Sie wird nach der Nutzung von `site.py` aus dem `sys`-Modul entfernt.
sys.getdefaultencoding()- Gibt die aktuelle <Standardcodierung> zurück.
Wenn nicht anders definiert oder gesetzt, ist die <Standardcodierung> standardmäßig ‘ascii’. Diese Codierung ist auch die Startstandardeinstellung von Python (und wirksam, bevor `site.py` ausgeführt wird).
Beachten Sie, dass das Standard-Startmodul `site.py` deaktivierten optionalen Code enthält, der die <Standardcodierung> gemäß der vom aktuellen Locale definierten Codierung setzen kann. Das `locale`-Modul wird verwendet, um die Codierung aus den Locale-Standardeinstellungen, die durch die Betriebssystemumgebung definiert sind (siehe `locale.py`), zu extrahieren. Wenn die Codierung nicht ermittelt werden kann, unbekannt oder nicht unterstützt ist, setzt der Code standardmäßig die <Standardcodierung> auf ‘ascii’. Um diesen Code zu aktivieren, bearbeiten Sie die Datei `site.py` oder platzieren Sie den entsprechenden Code im Modul `sitecustomize.py` Ihrer Python-Installation.
Unicode Konstruktoren
Python sollte einen integrierten Konstruktor für Unicode-Strings bereitstellen, der über __builtins__ verfügbar ist.
u = unicode(encoded_string[,encoding=<default encoding>][,errors="strict"])
u = u'<unicode-escape encoded Python string>'
u = ur'<raw-unicode-escape encoded Python string>'
Mit der als `unicode-escape` definierten Codierung
- Alle Nicht-Escape-Zeichen stellen sich selbst als Unicode-Ordnungszahlen dar (z.B. ‘a’ -> U+0061).
- Alle vorhandenen definierten Python-Escape-Sequenzen werden als Unicode-Ordnungszahlen interpretiert; beachten Sie, dass
\xXXXXalle Unicode-Ordnungszahlen darstellen kann und\OOO(oktal) Unicode-Ordnungszahlen bis U+01FF darstellen kann. - Eine neue Escape-Sequenz,
\uXXXX, stellt U+XXXX dar; es ist ein Syntaxfehler, wenn nach\uweniger als 4 Ziffern vorhanden sind.
Eine Erklärung möglicher Werte für Fehler finden Sie im Abschnitt Codecs unten.
Beispiele
u'abc' -> U+0061 U+0062 U+0063
u'\u1234' -> U+1234
u'abc\u1234\n' -> U+0061 U+0062 U+0063 U+1234 U+005c
Die Codierung ‘raw-unicode-escape’ ist wie folgt definiert:
\uXXXXSequenzen stellen das U+XXXX Unicode-Zeichen dar, wenn und nur wenn die Anzahl der führenden Backslashes ungerade ist.- Alle anderen Zeichen stellen sich selbst als Unicode-Ordnungszahlen dar (z.B. ‘b’ -> U+0062).
Beachten Sie, dass Sie einen Hinweis auf die Codierung geben sollten, die Sie zum Schreiben Ihrer Programme verwendet haben, z.B. als Pragmatische Zeile in einer der ersten Kommentarzeilen der Quelldatei (z.B. ‘# source file encoding: latin-1’). Wenn Sie nur 7-Bit-ASCII verwenden, ist alles in Ordnung und keine solche Benachrichtigung erforderlich, aber wenn Sie Latin-1-Zeichen aufnehmen, die nicht in ASCII definiert sind, kann es sich lohnen, einen Hinweis zu geben, da Menschen in anderen Ländern Ihre Quellzeichenfolgen ebenfalls lesen können möchten.
Unicode Typobjekt
Unicode-Objekte sollten den Typ `UnicodeType` mit dem Typnamen ‘unicode’ haben, der über das Standard-`types`-Modul verfügbar gemacht wird.
Unicode Ausgabe
Unicode-Objekte haben eine Methode `.encode([encoding=<Standardcodierung>])`, die einen Python-String zurückgibt, der den Unicode-String mit dem angegebenen Schema codiert (siehe Codecs).
print u := print u.encode() # using the <default encoding>
str(u) := u.encode() # using the <default encoding>
repr(u) := "u%s" % repr(u.encode('unicode-escape'))
Siehe auch `Internal Argument Parsing` und `Buffer Interface` für Details, wie andere in C geschriebene APIs Unicode-Objekte behandeln.
Unicode Ordnungszahlen
Da Unicode 3.0 einen 32-Bit-Ordnungszahlen-Zeichensatz hat, sollte die Implementierung 32-Bit-fähige Ordnungszahlen-Konvertierungs-APIs bereitstellen.
ord(u[:1]) (this is the standard ord() extended to work with Unicode
objects)
--> Unicode ordinal number (32-bit)
unichr(i)
--> Unicode object for character i (provided it is 32-bit);
ValueError otherwise
Beide APIs sollten in __builtins__ aufgenommen werden, genau wie ihre Gegenstücke für Strings ord() und chr().
Beachten Sie, dass Unicode Platz für private Codierungen bietet. Die Verwendung dieser kann zu unterschiedlichen Ausgabedarstellungen auf verschiedenen Maschinen führen. Dieses Problem ist kein Python- oder Unicode-Problem, sondern eines der Maschineneinrichtung und -wartung.
Vergleich & Hash-Wert
Unicode-Objekte sollten mit anderen Objekten gleich verglichen werden, nachdem diese anderen Objekte in Unicode konvertiert wurden. Für Strings bedeutet dies, dass sie als Unicode-Strings unter Verwendung der <Standardcodierung> interpretiert werden.
Unicode-Objekte sollten denselben Hash-Wert zurückgeben wie ihre ASCII-äquivalenten Strings. Unicode-Strings, die Nicht-ASCII-Werte enthalten, geben nicht garantiert dieselben Hash-Werte zurück wie die standardmäßig codierte äquivalente String-Repräsentation.
Beim Vergleich mit cmp() (oder PyObject_Compare()) sollte die Implementierung TypeErrors, die während der Konvertierung auftreten, maskieren, um mit dem Verhalten von Strings übereinzustimmen. Alle anderen Fehler, wie ValueErrors, die während der Konvertierung von Strings in Unicode auftreten, sollten nicht maskiert und an den Benutzer weitergegeben werden.
Bei Inklusionstests (‘a’ in u’abc’ und u’a’ in ‘abc’) sollten beide Seiten in Unicode konvertiert werden, bevor der Test angewendet wird. Fehler, die während der Konvertierung auftreten (z.B. `None` in u’abc’), sollten nicht maskiert werden.
Konvertierung (Coercion)
Die Verwendung von Python-Strings und Unicode-Objekten zur Bildung neuer Objekte sollte immer zur präziseren Form, d.h. zu Unicode-Objekten, konvertiert werden.
u + s := u + unicode(s)
s + u := unicode(s) + u
Alle String-Methoden sollten den Aufruf an eine äquivalente Unicode-Objektmethoden-Aufruf delegieren, indem alle beteiligten Strings in Unicode konvertiert und dann die Argumente an die Unicode-Methode gleichen Namens angewendet werden, z.B.
string.join((s,u),sep) := (s + sep) + u
sep.join((s,u)) := (s + sep) + u
Eine Diskussion über %-Formatierung in Bezug auf Unicode-Objekte finden Sie unter `Formatting Markers`.
Ausnahmen
UnicodeError ist im `exceptions`-Modul als Unterklasse von ValueError definiert. Es ist auf C-Ebene über PyExc_UnicodeError verfügbar. Alle Ausnahmen, die sich auf die Unicode-Codierung/-Decodierung beziehen, sollten Unterklassen von UnicodeError sein.
Codec (Coder/Decoder) Lookup
Eine Codec-Suchregistrierung (siehe `Codec Interface Definition`) sollte von einem Modul namens “codecs” implementiert werden.
codecs.register(search_function)
Suchfunktionen sollen ein Argument entgegennehmen, den Codierungsnamen in Kleinbuchstaben, wobei Bindestriche und Leerzeichen durch Unterstriche ersetzt werden, und ein Tupel von Funktionen zurückgeben (encoder, decoder, stream_reader, stream_writer), die die folgenden Argumente entgegennehmen:
- Encoder und Decoder
- Dies müssen Funktionen oder Methoden sein, die dieselbe Schnittstelle wie die Methoden
.encode/.decodevon Codec-Instanzen haben (siehe `Codec Interface`). Die Funktionen/Methoden sollen zustandslos arbeiten. - Stream-Reader und Stream-Writer
- Dies müssen Factory-Funktionen mit der folgenden Schnittstelle sein:
factory(stream,errors='strict')
Die Factory-Funktionen müssen Objekte zurückgeben, die die von
StreamWriter/StreamReaderbzw. definierten Schnittstellen bereitstellen (siehe `Codec Interface`). Stream-Codecs können einen Zustand beibehalten.Mögliche Werte für Fehler sind im Abschnitt Codecs unten definiert.
Wenn eine Suchfunktion eine gegebene Codierung nicht finden kann, sollte sie `None` zurückgeben.
Alias-Unterstützung für Codierungen liegt in der Verantwortung der Suchfunktionen.
Das `codecs`-Modul unterhält aus Performancegründen einen Codierungs-Cache. Codierungen werden zuerst im Cache gesucht. Wenn sie nicht gefunden werden, wird die Liste der registrierten Suchfunktionen durchlaufen. Wenn kein `codecs`-Tupel gefunden wird, wird ein `LookupError` ausgelöst. Andernfalls wird das `codecs`-Tupel im Cache gespeichert und an den Aufrufer zurückgegeben.
Um die Codec-Instanz abzufragen, sollte die folgende API verwendet werden:
codecs.lookup(encoding)
Dies gibt entweder das gefundene `codecs`-Tupel zurück oder löst einen LookupError aus.
Standard Codecs
Standard-Codecs sollten innerhalb eines `encodings/`-Paketverzeichnisses in der Standard-Python-Codebibliothek untergebracht werden. Die Datei __init__.py dieses Verzeichnisses sollte eine Codec-Lookup-kompatible Suchfunktion enthalten, die ein lazy Modul-basiertes Codec-Lookup implementiert.
Python sollte einige Standard-Codecs für die wichtigsten Codierungen bereitstellen, z.B.
'utf-8': 8-bit variable length encoding
'utf-16': 16-bit variable length encoding (little/big endian)
'utf-16-le': utf-16 but explicitly little endian
'utf-16-be': utf-16 but explicitly big endian
'ascii': 7-bit ASCII codepage
'iso-8859-1': ISO 8859-1 (Latin 1) codepage
'unicode-escape': See Unicode Constructors for a definition
'raw-unicode-escape': See Unicode Constructors for a definition
'native': Dump of the Internal Format used by Python
Gängige Aliase sollten ebenfalls standardmäßig bereitgestellt werden, z.B. ‘latin-1’ für ‘iso-8859-1’.
Hinweis: ‘utf-16’ sollte durch die Verwendung und Anforderung von Byte Order Marks (BOM) für die Dateieingabe/-ausgabe implementiert werden.
Alle anderen Codierungen, wie z.B. die CJK-Codierungen zur Unterstützung asiatischer Skripte, sollten in separaten Paketen implementiert werden, die nicht in die Kern-Python-Distribution aufgenommen werden und nicht Teil dieses Vorschlags sind.
Codec Schnittstellendefinition
Die folgende Basisklasse sollte im Modul “codecs” definiert werden. Sie bietet nicht nur Vorlagen für Implementierer von Codierungsmodulen, sondern definiert auch die Schnittstelle, die von der Unicode-Implementierung erwartet wird.
Beachten Sie, dass die hier definierte Codec-Schnittstelle für eine größere Bandbreite von Anwendungen gut geeignet ist. Die Unicode-Implementierung erwartet Unicode-Objekte als Eingabe für .encode() und .write() und Zeichenpuffer-kompatible Objekte als Eingabe für .decode(). Die Ausgabe von .encode() und .read() sollte ein Python-String sein, und .decode() muss ein Unicode-Objekt zurückgeben.
Zuerst haben wir die zustandslosen Encoder/Decoder. Diese arbeiten nicht in Chunks wie die Stream-Codecs (siehe unten), da alle Komponenten voraussichtlich im Speicher verfügbar sind.
class Codec:
"""Defines the interface for stateless encoders/decoders.
The .encode()/.decode() methods may implement different
error handling schemes by providing the errors argument.
These string values are defined:
'strict' - raise an error (or a subclass)
'ignore' - ignore the character and continue with the next
'replace' - replace with a suitable replacement character;
Python will use the official U+FFFD
REPLACEMENT CHARACTER for the builtin Unicode
codecs.
"""
def encode(self,input,errors='strict'):
"""Encodes the object input and returns a tuple (output
object, length consumed).
errors defines the error handling to apply. It
defaults to 'strict' handling.
The method may not store state in the Codec instance.
Use StreamCodec for codecs which have to keep state in
order to make encoding/decoding efficient.
"""
def decode(self,input,errors='strict'):
"""Decodes the object input and returns a tuple (output
object, length consumed).
input must be an object which provides the
bf_getreadbuf buffer slot. Python strings, buffer
objects and memory mapped files are examples of objects
providing this slot.
errors defines the error handling to apply. It
defaults to 'strict' handling.
The method may not store state in the Codec instance.
Use StreamCodec for codecs which have to keep state in
order to make encoding/decoding efficient.
"""
StreamWriter und StreamReader definieren die Schnittstelle für zustandsbehaftete Encoder/Decoder, die auf Streams arbeiten. Diese ermöglichen die Verarbeitung von Daten in Chunks, um den Speicher effizient zu nutzen. Wenn Sie große Strings im Speicher haben, möchten Sie sie möglicherweise mit cStringIO-Objekten wrappen und dann diese Codecs darauf anwenden, um ebenfalls Chunk-Verarbeitung zu ermöglichen, z.B. um dem Benutzer Fortschrittsinformationen bereitzustellen.
class StreamWriter(Codec):
def __init__(self,stream,errors='strict'):
"""Creates a StreamWriter instance.
stream must be a file-like object open for writing
(binary) data.
The StreamWriter may implement different error handling
schemes by providing the errors keyword argument.
These parameters are defined:
'strict' - raise a ValueError (or a subclass)
'ignore' - ignore the character and continue with the next
'replace'- replace with a suitable replacement character
"""
self.stream = stream
self.errors = errors
def write(self,object):
"""Writes the object's contents encoded to self.stream.
"""
data, consumed = self.encode(object,self.errors)
self.stream.write(data)
def writelines(self, list):
"""Writes the concatenated list of strings to the stream
using .write().
"""
self.write(''.join(list))
def reset(self):
"""Flushes and resets the codec buffers used for keeping state.
Calling this method should ensure that the data on the
output is put into a clean state, that allows appending
of new fresh data without having to rescan the whole
stream to recover state.
"""
pass
def __getattr__(self,name, getattr=getattr):
"""Inherit all other methods from the underlying stream.
"""
return getattr(self.stream,name)
class StreamReader(Codec):
def __init__(self,stream,errors='strict'):
"""Creates a StreamReader instance.
stream must be a file-like object open for reading
(binary) data.
The StreamReader may implement different error handling
schemes by providing the errors keyword argument.
These parameters are defined:
'strict' - raise a ValueError (or a subclass)
'ignore' - ignore the character and continue with the next
'replace'- replace with a suitable replacement character;
"""
self.stream = stream
self.errors = errors
def read(self,size=-1):
"""Decodes data from the stream self.stream and returns the
resulting object.
size indicates the approximate maximum number of bytes
to read from the stream for decoding purposes. The
decoder can modify this setting as appropriate. The
default value -1 indicates to read and decode as much
as possible. size is intended to prevent having to
decode huge files in one step.
The method should use a greedy read strategy meaning
that it should read as much data as is allowed within
the definition of the encoding and the given size, e.g.
if optional encoding endings or state markers are
available on the stream, these should be read too.
"""
# Unsliced reading:
if size < 0:
return self.decode(self.stream.read())[0]
# Sliced reading:
read = self.stream.read
decode = self.decode
data = read(size)
i = 0
while 1:
try:
object, decodedbytes = decode(data)
except ValueError,why:
# This method is slow but should work under pretty
# much all conditions; at most 10 tries are made
i = i + 1
newdata = read(1)
if not newdata or i > 10:
raise
data = data + newdata
else:
return object
def readline(self, size=None):
"""Read one line from the input stream and return the
decoded data.
Note: Unlike the .readlines() method, this method
inherits the line breaking knowledge from the
underlying stream's .readline() method -- there is
currently no support for line breaking using the codec
decoder due to lack of line buffering. Subclasses
should however, if possible, try to implement this
method using their own knowledge of line breaking.
size, if given, is passed as size argument to the
stream's .readline() method.
"""
if size is None:
line = self.stream.readline()
else:
line = self.stream.readline(size)
return self.decode(line)[0]
def readlines(self, sizehint=0):
"""Read all lines available on the input stream
and return them as list of lines.
Line breaks are implemented using the codec's decoder
method and are included in the list entries.
sizehint, if given, is passed as size argument to the
stream's .read() method.
"""
if sizehint is None:
data = self.stream.read()
else:
data = self.stream.read(sizehint)
return self.decode(data)[0].splitlines(1)
def reset(self):
"""Resets the codec buffers used for keeping state.
Note that no stream repositioning should take place.
This method is primarily intended to be able to recover
from decoding errors.
"""
pass
def __getattr__(self,name, getattr=getattr):
""" Inherit all other methods from the underlying stream.
"""
return getattr(self.stream,name)
Implementierer von Stream-Codecs können die Schnittstellen StreamWriter und StreamReader zu einer Klasse kombinieren. Selbst die Kombination aller dieser mit der `Codec`-Klasse sollte möglich sein.
Implementierer können zusätzliche Methoden hinzufügen, um die Funktionalität des Codecs zu erweitern oder zusätzliche Zustandsinformationen bereitzustellen, die für ihre Arbeit benötigt werden. Die interne Codec-Implementierung wird jedoch nur die oben genannten Schnittstellen verwenden.
Es ist für die Unicode-Implementierung nicht erforderlich, diese Basisklassen zu verwenden, nur die Schnittstellen müssen übereinstimmen; dies erlaubt die Erstellung von Codecs als Erweiterungstypen.
Als Richtlinie sollten große Mapping-Tabellen mit statischen C-Daten in separaten (gemeinsamen) Erweiterungsmodulen implementiert werden. Auf diese Weise können mehrere Prozesse dieselben Daten teilen.
Ein Werkzeug zur automatischen Konvertierung von Unicode-Mapping-Dateien in Mapping-Module sollte bereitgestellt werden, um die Unterstützung für zusätzliche Mappings zu vereinfachen (siehe `References`).
Leerzeichen
Die Methode .split() muss wissen, was als Whitespace in Unicode gilt.
Groß-/Kleinschreibung
Die Konvertierung von Groß- und Kleinschreibung ist bei Unicode-Daten ziemlich kompliziert, da viele verschiedene Bedingungen zu beachten sind. Siehe
für einige Richtlinien zur Implementierung der Groß-/Kleinschreibung.
Für Python sollten wir nur die 1:1-Konvertierungen implementieren, die in Unicode enthalten sind. Locale-abhängige und andere Sonderfallkonvertierungen (siehe die Unicode-Standarddatei `SpecialCasing.txt`) sollten in den Benutzerbereich (user land) Routinen verbleiben und nicht in den Kern-Interpreter aufgenommen werden.
Die Methoden .capitalize() und .iscapitalized() sollten dem in dem oben genannten technischen Bericht definierten Algorithmus zur Groß-/Kleinschreibung so genau wie möglich folgen.
Zeilenumbrüche
Zeilenumbrüche sollten für alle Unicode-Zeichen mit der Eigenschaft B sowie für die Kombinationen CRLF, CR, LF (in dieser Reihenfolge interpretiert) und andere spezielle Zeilentrennzeichen, die vom Standard definiert sind, erfolgen.
Der Unicode-Typ sollte eine Methode .splitlines() bereitstellen, die eine Liste von Zeilen gemäß der obigen Spezifikation zurückgibt. Siehe `Unicode Methods`.
Unicode Zeicheneigenschaften
Ein separates Modul “unicodedata” sollte eine kompakte Schnittstelle zu allen Unicode-Zeicheneigenschaften bereitstellen, die in der Datei `UnicodeData.txt` des Standards definiert sind.
Diese Eigenschaften bieten unter anderem Möglichkeiten, Zahlen, Ziffern, Leerzeichen, Whitespace usw. zu erkennen.
Da dieses Modul Zugriff auf alle Unicode-Zeichen bieten muss, muss es schließlich die Daten aus `UnicodeData.txt` enthalten, die etwa 600 KB beanspruchen. Aus diesem Grund sollten die Daten in statischen C-Daten gespeichert werden. Dies ermöglicht die Kompilierung als gemeinsam genutztes Modul, das vom zugrunde liegenden Betriebssystem zwischen Prozessen geteilt werden kann (im Gegensatz zu normalen Python-Code-Modulen).
Es sollte eine Standard-Python-Schnittstelle für den Zugriff auf diese Informationen geben, damit andere Implementierer ihre eigenen, möglicherweise erweiterten Versionen einbinden können, z.B. solche, die die Daten zur Laufzeit dekomprimieren.
Private Code Point Bereiche
Die Unterstützung hierfür bleibt Benutzercodes und ist nicht explizit in den Kern integriert. Beachten Sie, dass aufgrund der Implementierung des internen Formats nur der Bereich zwischen \uE000 und \uF8FF für private Codierungen nutzbar ist.
Internes Format
Das interne Format für Unicode-Objekte sollte ein Python-spezifisches festes Format <PythonUnicode> verwenden, das als ‘unsigned short’ (oder ein anderer vorzeichenloser numerischer Typ mit 16 Bit) implementiert ist. Die Byte-Reihenfolge ist plattformabhängig.
Dieses Format speichert UTF-16-Codierungen der entsprechenden Unicode-Ordnungszahlen. Die Python-Unicode-Implementierung greift auf diese Werte zu, als wären sie UCS-2-Werte. UCS-2 und UTF-16 sind für alle derzeit definierten Unicode-Zeichenpunkte identisch. UTF-16 ohne Surrogates ermöglicht den Zugriff auf etwa 64.000 Zeichen und deckt alle Zeichen in der Basic Multilingual Plane (BMP) von Unicode ab.
Es liegt in der Verantwortung des Codecs sicherzustellen, dass die Daten, die er an den Unicode-Objektkonstruktor übergibt, diese Annahme respektieren. Der Konstruktor prüft die Daten nicht auf Unicode-Konformität oder Verwendung von Surrogates.
Zukünftige Implementierungen können die 32-Bit-Beschränkung auf den gesamten Satz aller UTF-16-adressierbaren Zeichen (rund 1 Million Zeichen) erweitern.
Die Unicode-API sollte Schnittstellenroutinen von <PythonUnicode> zum `wchar_t` des Compilers bereitstellen, der je nach verwendetem Compiler/libc/Plattform 16 oder 32 Bit sein kann.
Unicode-Objekte sollten einen Zeiger auf ein zwischengespeichertes Python-String-Objekt <defenc> haben, das den Wert des Objekts unter Verwendung der <Standardcodierung> enthält. Dies ist aus Performance- und Gründen der internen Argumentanalyse (siehe `Internal Argument Parsing`) erforderlich. Der Puffer wird gefüllt, wenn die erste Konvertierungsanforderung an die <Standardcodierung> auf dem Objekt ausgegeben wird.
Interning ist (vorerst) nicht erforderlich, da Python-Identifikatoren als rein ASCII definiert sind.
codecs.BOM sollte die Byte Order Mark (BOM) für das intern verwendete Format zurückgeben. Das `codecs`-Modul sollte die folgenden zusätzlichen Konstanten zur Bequemlichkeit und Referenz bereitstellen (codecs.BOM wird je nach Plattform entweder BOM_BE oder BOM_LE sein)
BOM_BE: '\376\377'
(corresponds to Unicode U+0000FEFF in UTF-16 on big endian
platforms == ZERO WIDTH NO-BREAK SPACE)
BOM_LE: '\377\376'
(corresponds to Unicode U+0000FFFE in UTF-16 on little endian
platforms == defined as being an illegal Unicode character)
BOM4_BE: '\000\000\376\377'
(corresponds to Unicode U+0000FEFF in UCS-4)
BOM4_LE: '\377\376\000\000'
(corresponds to Unicode U+0000FFFE in UCS-4)
Beachten Sie, dass Unicode Big-Endian-Byte-Reihenfolge als "korrekt" betrachtet. Die vertauschte Reihenfolge wird als Indikator für ein "falsches" Format genommen, daher die Definition des illegalen Zeichens.
Das Konfigurationsskript sollte Hilfe bei der Entscheidung leisten, ob Python den nativen wchar_t-Typ verwenden kann oder nicht (er muss ein 16-Bit-vorzeichenloser Typ sein).
Puffer-Schnittstelle
Implementieren Sie die Puffer-Schnittstelle unter Verwendung des <defenc> Python-String-Objekts als Basis für bf_getcharbuf und des internen Puffers für bf_getreadbuf. Wenn bf_getcharbuf angefordert wird und das <defenc>-Objekt noch nicht existiert, wird es zuerst erstellt.
Beachten Sie, dass als Sonderfall der Parser-Marker “s#” keine rohen Unicode UTF-16-Daten zurückgibt (was bf_getreadbuf zurückgibt), sondern stattdessen versucht, das Unicode-Objekt unter Verwendung der Standardcodierung zu codieren und dann einen Zeiger auf das resultierende String-Objekt zurückgibt (oder eine Ausnahme auslöst, falls die Konvertierung fehlschlägt). Dies wurde getan, um versehentliches Schreiben von Binärdaten in einen Ausgabestream zu verhindern, den die Gegenseite möglicherweise nicht erkennt.
Dies hat den Vorteil, dass ohne zusätzliche Angabe der zu verwendenden Codierung in Ausgabeströme (die diese Schnittstelle typischerweise verwenden) geschrieben werden kann.
Wenn Sie auf die Lese-Puffer-Schnittstelle von Unicode-Objekten zugreifen müssen, verwenden Sie die PyObject_AsReadBuffer() Schnittstelle.
Das interne Format kann auch über den ‘unicode-internal’ Codec zugegriffen werden, z.B. über u.encode('unicode-internal').
Pickle/Marshalling
Sollte native Unicode-Objektunterstützung haben. Die Objekte sollten mittels plattformunabhängiger Codierungen codiert werden.
Marshal sollte UTF-8 verwenden und Pickle sollte entweder Raw-Unicode-Escape (im Textmodus) oder UTF-8 (im Binärmodus) als Codierung wählen. Die Verwendung von UTF-8 anstelle von UTF-16 hat den Vorteil, dass die Notwendigkeit entfällt, eine BOM-Markierung zu speichern.
Reguläre Ausdrücke
Secret Labs AB arbeitet an einer Unicode-fähigen regulären Ausdrucksmaschine. Sie funktioniert auf reinen 8-Bit-, UCS-2- und (optional) UCS-4-internen Zeichenpuffern.
Siehe auch
für einige Anmerkungen zur Behandlung von Unicode-REs.
Formatierungsmarker
Formatierungsmarker werden in Python-Formatstrings verwendet. Wenn Python-Strings als Formatstrings verwendet werden, sollten die folgenden Interpretationen gelten:
'%s': For Unicode objects this will cause coercion of the
whole format string to Unicode. Note that you should use
a Unicode format string to start with for performance
reasons.
Wenn der Formatstring ein Unicode-Objekt ist, werden alle Parameter zuerst in Unicode konvertiert, dann zusammengefügt und gemäß dem Formatstring formatiert. Zahlen werden zuerst in Strings und dann in Unicode konvertiert.
'%s': Python strings are interpreted as Unicode
string using the <default encoding>. Unicode objects are
taken as is.
Alle anderen String-Formatierer sollten entsprechend funktionieren.
Beispiel
u"%s %s" % (u"abc", "abc") == u"abc abc"
Internes Argument Parsen
Diese Marker werden von den PyArg_ParseTuple() APIs verwendet.
- “U”
- Prüft auf ein Unicode-Objekt und gibt einen Zeiger darauf zurück.
- “s”
- Für Unicode-Objekte: Gibt einen Zeiger auf den <defenc>-Puffer des Objekts zurück (der die <Standardcodierung> verwendet).
- “s#”
- Zugriff auf die standardmäßig codierte Version des Unicode-Objekts (siehe `Buffer Interface`); beachten Sie, dass sich die Länge auf die Länge des standardmäßig codierten Strings bezieht und nicht auf die Länge des Unicode-Objekts.
- “t#”
- Gleich wie “s#”.
- “es”
- Nimmt zwei Parameter: Codierung (
const char *) und Puffer (char **).Das Eingabeobjekt wird zuerst auf übliche Weise in Unicode konvertiert und dann mit der angegebenen Codierung in einen String codiert.
Bei der Ausgabe wird ein Puffer der benötigten Größe allokiert und über
*bufferals NULL-terminierter String zurückgegeben. Der Codierte darf keine eingebetteten NULL-Zeichen enthalten. Der Aufrufer ist dafür verantwortlich,PyMem_Free()aufzurufen, um den allokierten*buffernach der Verwendung freizugeben. - “es#”
- Nimmt drei Parameter: Codierung (
const char *), Puffer (char **) und buffer_len (int *).Das Eingabeobjekt wird zuerst auf übliche Weise in Unicode konvertiert und dann mit der angegebenen Codierung in einen String codiert.
Wenn
*buffernicht NULL ist, muss*buffer_lenbei der Eingabe aufsizeof(buffer)gesetzt werden. Die Ausgabe wird dann in*bufferkopiert.Wenn
*bufferNULL ist, wird ein Puffer der benötigten Größe allokiert und die Ausgabe hineinkopiert.*bufferwird dann aktualisiert, um auf den allokierten Speicherbereich zu zeigen. Der Aufrufer ist dafür verantwortlich,PyMem_Free()aufzurufen, um den allokierten*buffernach der Verwendung freizugeben.In beiden Fällen wird
*buffer_lenauf die Anzahl der geschriebenen Zeichen (ohne das abschließende NULL-Byte) aktualisiert. Der Ausgabepuffer ist garantiert NULL-terminiert.
Beispiele
Verwendung von “es#” mit automatischer Allokation
static PyObject *
test_parser(PyObject *self,
PyObject *args)
{
PyObject *str;
const char *encoding = "latin-1";
char *buffer = NULL;
int buffer_len = 0;
if (!PyArg_ParseTuple(args, "es#:test_parser",
encoding, &buffer, &buffer_len))
return NULL;
if (!buffer) {
PyErr_SetString(PyExc_SystemError,
"buffer is NULL");
return NULL;
}
str = PyString_FromStringAndSize(buffer, buffer_len);
PyMem_Free(buffer);
return str;
}
Verwendung von “es” mit automatischer Allokation, die einen NULL-terminierten String zurückgibt
static PyObject *
test_parser(PyObject *self,
PyObject *args)
{
PyObject *str;
const char *encoding = "latin-1";
char *buffer = NULL;
if (!PyArg_ParseTuple(args, "es:test_parser",
encoding, &buffer))
return NULL;
if (!buffer) {
PyErr_SetString(PyExc_SystemError,
"buffer is NULL");
return NULL;
}
str = PyString_FromString(buffer);
PyMem_Free(buffer);
return str;
}
Verwendung von “es#” mit einem vorab allokierten Puffer
static PyObject *
test_parser(PyObject *self,
PyObject *args)
{
PyObject *str;
const char *encoding = "latin-1";
char _buffer[10];
char *buffer = _buffer;
int buffer_len = sizeof(_buffer);
if (!PyArg_ParseTuple(args, "es#:test_parser",
encoding, &buffer, &buffer_len))
return NULL;
if (!buffer) {
PyErr_SetString(PyExc_SystemError,
"buffer is NULL");
return NULL;
}
str = PyString_FromStringAndSize(buffer, buffer_len);
return str;
}
Datei/Stream Ausgabe
Da `file.write(object)` und die meisten anderen Stream-Writer den Argument-Parsing-Marker “s#” oder “t#” zum Abfragen der zu schreibenden Daten verwenden, wird die standardmäßig codierte String-Version des Unicode-Objekts in die Streams geschrieben (siehe `Buffer Interface`).
Für die explizite Behandlung von Dateien mit Unicode sollten die Standard-Stream-Codecs, wie sie über das `codecs`-Modul verfügbar sind, verwendet werden.
Das `codecs`-Modul sollte eine Abkürzungsfunktion `open(filename, mode, encoding)` bereitstellen, die auch sicherstellt, dass der `mode` das Zeichen ‘b’ enthält, wenn nötig.
Datei/Stream Eingabe
Nur der Benutzer weiß, welche Codierung die Eingabedaten verwenden, daher wird keine spezielle Magie angewendet. Der Benutzer muss die String-Daten explizit in Unicode-Objekte konvertieren, wenn nötig, oder die in den `codecs`-Modul definierten Datei-Wrapper verwenden (siehe `File/Stream Output`).
Unicode Methoden & Attribute
Alle Python-String-Methoden, plus
.encode([encoding=<default encoding>][,errors="strict"])
--> see Unicode Output
.splitlines([include_breaks=0])
--> breaks the Unicode string into a list of (Unicode) lines;
returns the lines with line breaks included, if
include_breaks is true. See Line Breaks for a
specification of how line breaking is done.
Code Basis
Wir sollten die Unicode-Objektimplementierung von Fredrik Lundh als Grundlage verwenden. Sie implementiert bereits die meisten benötigten String-Methoden und bietet eine gut geschriebene Codebasis, auf der wir aufbauen können.
Die in Fredriks Implementierung implementierte Objekt-Teilung sollte fallen gelassen werden.
Testfälle
Testfälle sollten denen in Lib/test/test_string.py folgen und zusätzliche Prüfungen für die Codec-Registry und die Standard-Codecs enthalten.
Referenzen
- Unicode Consortium: http://www.unicode.org/
- Unicode FAQ: http://www.unicode.org/unicode/faq/
- Unicode 3.0: http://www.unicode.org/unicode/standard/versions/Unicode3.0.html
- Unicode-TechReports: http://www.unicode.org/unicode/reports/techreports.html
- Unicode-Mappings: ftp://ftp.unicode.org/Public/MAPPINGS/
- Einführung in Unicode (etwas veraltet, aber immer noch gut lesbar): http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html
- Zum Vergleich: Einführung von Unicode in ECMAScript (aka JavaScript) – http://www-4.ibm.com/software/developer/library/internationalization-support.html
- IANA Zeichensetznahmen: ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
- Diskussion über UTF-8 und Unicode-Unterstützung für POSIX und Linux: http://www.cl.cam.ac.uk/~mgk25/unicode.html
- Codierungen
- Übersicht: http://czyborra.com/utf/
- UCS-2: http://www.uazone.org/multiling/unicode/ucs2.html
- UTF-7: Definiert in RFC 2152
- UTF-8: Definiert in RFC 2279
- UTF-16: http://www.uazone.org/multiling/unicode/wg2n1035.html
Geschichte dieses Vorschlags
[ed. Anm.: Überarbeitungen vor Version 1.7 sind im CVS-Verlauf von Misc/unicode.txt aus der Standard-Python-Distribution verfügbar. Der gesamte nachfolgende Verlauf ist über die CVS-Revisionen dieser Datei verfügbar.]
1.7
- Anmerkung zum geänderten Verhalten von “s#” hinzugefügt.
1.6
- <defencstr> in <defenc> geändert, da dies der im Implementierung verwendete Name ist.
- Anmerkungen zur Verwendung von <defenc> in der Pufferprotokoll-Implementierung hinzugefügt.
1.5
- Anmerkungen zum Setzen der <Standardcodierung> hinzugefügt.
- Einige Tippfehler korrigiert (danke an Andrew Kuchling).
- <defencstr> in <utf8str> geändert.
1.4
- Anmerkung zu Vergleichen von gemischten Typen und Inklusionstests hinzugefügt.
- Die Behandlung von Unicode-Objekten in Formatstrings geändert (wenn sie mit
'%s' % uverwendet werden, wird der Formatstring nun in Unicode konvertiert, was ein Unicode-Objekt als Rückgabe ergibt). - Link zu IANA-Charset-Namen hinzugefügt (danke an Lars Marius Garshol).
- Neue Codec-Methoden
.readline(),.readlines()und.writelines()hinzugefügt.
1.3
- Neue Parser-Marker “es” und “es#” hinzugefügt.
1.2
- POD zu
codecs.open()entfernt.
1.1
- Anmerkung zu Vergleichen und Hash-Werten hinzugefügt.
- Anmerkung zu Groß-/Kleinschreibungsalgorithmen hinzugefügt.
- Stream-Codec-Methoden
.read()und.write()geändert, um den Standard-Datei-ähnlichen Objektmethoden zu entsprechen (Informationen über verbrauchte Bytes werden von den Methoden nicht mehr zurückgegeben).
1.0
- Encode-Codec-Methode wurde symmetrisch zur Decode-Methode geändert (sie geben jetzt beide (Objekt, verbrauchte Daten) zurück und werden somit austauschbar).
- Die Methode
__init__der `Codec`-Klasse entfernt (die Methoden sind zustandslos) und das `errors`-Argument nach unten zu den Methoden verschoben; - Das Codec-Design wurde generischer in Bezug auf die Art der Eingabe- und Ausgabeobjekte gestaltet;
StreamWriter.flushinStreamWriter.resetumbenannt, um die.flush()Methode des Streams nicht zu überschreiben;- `.breaklines()` wurde in `.splitlines()` umbenannt;
- Das Modul `unicodec` wurde in `codecs` umbenannt;
- Der Abschnitt Datei-I/O wurde geändert, um auf die Stream-Codecs zu verweisen.
0.9
- Das Schlüsselwortargument `errors` wurde geändert;
- ‘replace’-Fehlerbehandlung hinzugefügt;
- Die Codec-APIs wurden geändert, um Puffer-ähnliche Objekte als Eingabe zu akzeptieren;
- einige kleinere Tippfehler behoben;
- Abschnitt `Whitespace` hinzugefügt und Referenzen für Unicode-Zeichen mit den Merkmalen Whitespace und Zeilenumbruch aufgenommen;
- Anmerkung hinzugefügt, dass Suchfunktionen kleingeschriebene Codierungsnamen erwarten können;
- Slicing und Offsets in den Codec-APIs gestrichen.
0.8
- Das `encodings`-Paket und die `raw_unicode_escape`-Codierung hinzugefügt;
- Das Dokument wurde untabifiziert;
- Anmerkungen zu Unicode-Formatstrings hinzugefügt;
- Methode
.breaklines()hinzugefügt.
0.7
- Ein komplett neuer Satz von Codec-APIs hinzugefügt;
- Ein anderes Encoder-Lookup-Schema hinzugefügt;
- Einige Namen korrigiert.
0.6
- “s#” zu “t#” geändert;
- <defencbuf> zu <defencstr> geändert, das ein echtes Python-String-Objekt enthält;
- Die Puffer-Schnittstelle wurde geändert, um Anfragen an die Puffer-Schnittstelle von <defencstr> zu delegieren;
- Der explizite Verweis auf das `unicodec.codecs`-Wörterbuch wurde entfernt (das Modul kann dies auf eine für den Zweck geeignete Weise implementieren);
- Die einstellbare Standardcodierung wurde entfernt.
- verschiebe
UnicodeErrorvon unicodec nach exceptions; - „s#“ gibt nicht die internen Daten zurück;
- UCS-2/UTF-16-Prüfung vom Unicode-Konstruktor zum Codecs verschoben
0.5
- verschob
sys.bomzuunicodec.BOM; - Abschnitte zu Groß-/Kleinschreibung hinzugefügt,
- private Benutzercodierungen und Unicode-Zeicheneigenschaften
0.4
- Codec-Schnittstelle hinzugefügt, Notizen zur %-Formatierung,
- einige Kodierungsdetails geändert,
- Kommentare zu Stream-Wrappern hinzugefügt,
- einige Diskussionspunkte behoben (am wichtigsten: Internes Format),
- die Kodierung „unicode-escape“ geklärt, Kodierungsreferenzen hinzugefügt
0.3
- Referenzen, Kommentare zu Codec-Modulen, dem internen Format, bf_getcharbuffer und der RE-Engine hinzugefügt;
- die von Tim Peters vorgeschlagene Kodierung „unicode-escape“ hinzugefügt und repr(u) entsprechend korrigiert
0.2
- Guido's Vorschläge integriert, Stream-Codecs und Datei-Wrapping hinzugefügt
0.1
- erste Version
Quelle: https://github.com/python/peps/blob/main/peps/pep-0100.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT