Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 261 – Unterstützung für „breite“ Unicode-Zeichen

Autor:
Paul Prescod <paul at prescod.net>
Status:
Final
Typ:
Standards Track
Erstellt:
27. Jun 2001
Python-Version:
2.2
Post-History:
27. Jun 2001

Inhaltsverzeichnis

Zusammenfassung

Python 2.1 Unicode-Zeichen können nur Ordnungszahlen bis 2**16 - 1 haben. Dieser Bereich entspricht einem Bereich in Unicode, der als Basic Multilingual Plane (BMP) bekannt ist. Es gibt jetzt Zeichen in Unicode, die auf anderen „Ebenen“ liegen. Das größte adressierbare Zeichen in Unicode hat die Ordnungszahl 17 * 2**16 - 1 (0x10ffff). Zur besseren Lesbarkeit werden wir dies TOPCHAR nennen und Zeichen in diesem Bereich „breite Zeichen“ nennen.

Glossar

Zeichen
Alleine verwendet, bedeutet es die adressierbaren Einheiten eines Python-Unicode-Strings.
Codepunkt
Ein Codepunkt ist eine Ganzzahl zwischen 0 und TOPCHAR. Wenn Sie sich Unicode als eine Zuordnung von Ganzzahlen zu Zeichen vorstellen, ist jede Ganzzahl ein Codepunkt. Aber auch die Ganzzahlen zwischen 0 und TOPCHAR, die keinen Zeichen zugeordnet sind, sind Codepunkte. Einige werden eines Tages für Zeichen verwendet werden. Einige werden garantiert niemals für Zeichen verwendet werden.
Codec
Eine Sammlung von Funktionen zur Übersetzung zwischen physischen Kodierungen (z. B. auf der Festplatte oder aus dem Netzwerk kommend) und logischen Python-Objekten.
Kodierung
Mechanismus zur Darstellung abstrakter Zeichen in Form von physischen Bits und Bytes. Kodierungen ermöglichen es uns, Unicode-Zeichen auf der Festplatte zu speichern und sie über Netzwerke zu übertragen, auf eine Weise, die mit anderer Unicode-Software kompatibel ist.
Surrogat-Paar
Zwei physische Zeichen, die ein einzelnes logisches Zeichen darstellen. Teil einer Konvention zur Darstellung von 32-Bit-Codepunkten in Form von zwei 16-Bit-Codepunkten.
Unicode-String
Ein Python-Typ, der eine Sequenz von Codepunkten mit „String-Semantik“ darstellt (z. B. Groß-/Kleinschreibungsumwandlung, Kompatibilität mit regulären Ausdrücken usw.). Konstruiert mit der Funktion unicode().

Vorgeschlagene Lösung

Eine Lösung wäre, lediglich die maximale Ordnungszahl auf einen größeren Wert zu erhöhen. Leider besteht die einzige direkte Implementierung dieser Idee darin, 4 Bytes pro Zeichen zu verwenden. Dies hat zur Folge, dass die meisten Unicode-Strings doppelt so groß werden. Um diese Kosten nicht jedem Benutzer aufzuerlegen, erlaubt Python 2.2 die 4-Byte-Implementierung als Build-Option. Benutzer können wählen, ob sie breite Zeichen benötigen oder Speicherplatz sparen möchten.

Die 4-Byte-Option wird als „breites Py_UNICODE“ bezeichnet. Die 2-Byte-Option wird als „schmales Py_UNICODE“ bezeichnet.

Die meisten Dinge werden sich in der breiten und schmalen Welt identisch verhalten.

  • unichr(i) für 0 <= i < 2**16 (0x10000) gibt immer einen String der Länge eins zurück.
  • unichr(i) für 2**16 <= i <= TOPCHAR gibt auf breiten Python-Builds einen String der Länge eins zurück. Auf schmalen Builds wird ValueError ausgelöst.

    PROBLEM

    Python erlaubt derzeit \U-Literale, die nicht als einzelnes Python-Zeichen dargestellt werden können. Es erzeugt zwei Python-Zeichen, die als „Surrogat-Paar“ bezeichnet werden. Sollte dies bei zukünftigen schmalen Python-Builds verboten werden?

    Dafür

    Python erlaubt bereits die Erstellung eines Surrogat-Paares für eine lange Unicode-Literal-Zeichen-Escape-Sequenz. Dies ist im Grunde als einfache Möglichkeit konzipiert, „breite Zeichen“ auch in einem schmalen Python-Build zu erstellen. Es ist auch einigermaßen logisch, da die Syntax für Unicode-Literale im Grunde eine Kurzform zur Aufrufung des Unicode-Escape-Codecs ist.

    Dagegen

    Surrogate könnten auf diese Weise leicht erstellt werden, aber der Benutzer muss immer noch vorsichtig beim Slicing, Indexieren, Drucken usw. sein. Daher haben einige vorgeschlagen, dass Unicode-Literale keine Surrogate unterstützen sollten.

    PROBLEM

    Sollte Python die Erstellung von Zeichen erlauben, die keinen Unicode-Codepunkten entsprechen? Nicht zugewiesene Unicode-Codepunkte sollten offensichtlich legal sein (da sie jederzeit zugewiesen werden könnten). Aber Codepunkte über TOPCHAR hinaus werden garantiert niemals von Unicode verwendet. Sollten wir ihnen trotzdem Zugriff gewähren?

    Dafür

    Wenn ein Python-Benutzer glaubt, dass er weiß, was er tut, warum sollten wir versuchen, ihn daran zu hindern, die Unicode-Spezifikation zu verletzen? Immerhin hindern wir 8-Bit-Strings nicht daran, Nicht-ASCII-Zeichen zu enthalten.

    Dagegen

    Codecs und anderer Unicode-verbrauchender Code muss vorsichtig mit diesen Zeichen sein, die von der Unicode-Spezifikation verboten sind.
  • ord() ist immer die Umkehrfunktion von unichr()
  • Es gibt im sys-Modul einen Ganzzahlwert, der die größte Ordnungszahl für ein Zeichen in einem Unicode-String im aktuellen Interpreter beschreibt. sys.maxunicode ist 2**16-1 (0xffff) auf schmalen Python-Builds und TOPCHAR auf breiten Builds.

    PROBLEM

    Sollte es separate Konstanten für den Zugriff auf TOPCHAR und die tatsächliche Obergrenze für die Domäne von unichr geben (falls sie sich unterscheiden)? Es gab auch den Vorschlag für sys.unicodewidth, das die Werte 'wide' und 'narrow' annehmen kann.
  • Jedes Python-Unicode-Zeichen repräsentiert genau einen Unicode-Codepunkt (d. h. Python-Unicode-Zeichen = Abstraktes Unicode-Zeichen).
  • Codecs werden aufgerüstet, um „breite Zeichen“ zu unterstützen (direkt in UCS-4 dargestellt und als variable Längen-Sequenzen in UTF-8 und UTF-16). Dies ist der Hauptteil der noch zu erledigenden Implementierung.
  • Es gibt eine Konvention in der Unicode-Welt, einen 32-Bit-Codepunkt in Form von zwei 16-Bit-Codepunkten zu kodieren. Diese werden als „Surrogat-Paare“ bezeichnet. Pythons Codecs werden diese Konvention übernehmen und 32-Bit-Codepunkte als Surrogat-Paare auf schmalen Python-Builds kodieren.

    PROBLEM

    Sollte es eine Möglichkeit geben, Codecs anzuweisen, keine Surrogat-Zeichen zu generieren und stattdessen breite Zeichen als Fehler zu behandeln?

    Dafür

    Ich möchte vielleicht Code schreiben, der nur mit festen Zeichenbreiten funktioniert und sich nicht um Surrogate kümmern muss.

    Dagegen

    Kein klarer Vorschlag, wie dies an Codecs kommuniziert werden soll.
  • Es gibt keine Einschränkungen bei der Erstellung von Strings, die „für Surrogate reservierte“ Codepunkte falsch verwenden. Diese werden als „isolierte Surrogate“ bezeichnet. Die Codecs sollten das Lesen dieser aus Dateien verbieten, aber Sie könnten sie mit Zeichenketten-Literalen oder unichr() erstellen.

Implementierung

Es gibt eine neue Definition

#define Py_UNICODE_SIZE 2

Um zu testen, ob UCS2 oder UCS4 verwendet wird, sollte das abgeleitete Makro Py_UNICODE_WIDE verwendet werden, das definiert ist, wenn UCS-4 verwendet wird.

Es gibt eine neue Konfigurationsoption

–enable-unicode=ucs2 konfiguriert ein schmales Py_UNICODE und verwendet wchar_t, wenn es passt
–enable-unicode=ucs4 konfiguriert ein breites Py_UNICODE und verwendet wchar_t, wenn es passt
–enable-unicode gleichbedeutend mit „=ucs2“
–disable-unicode entfernt die Unicode-Funktionalität vollständig.

Es wird auch vorgeschlagen, dass eines Tages --enable-unicode standardmäßig die Breite von wchar_t Ihrer Plattform verwendet.

Windows-Builds werden eine Weile schmal sein, basierend auf der Tatsache, dass es wenige Anfragen nach breiten Zeichen gab, diese Anfragen hauptsächlich von Hardcore-Programmierern stammen, die ihre eigenen Python-Versionen kaufen können, und Windows selbst stark auf 16-Bit-Zeichen ausgerichtet ist.

Anmerkungen

Dieser PEP impliziert NICHT, dass Benutzer von Unicode eine 4-Byte-Kodierung für ihre Dateien auf der Festplatte oder im Netzwerk verwenden müssen. Er erlaubt ihnen nur, dies zu tun. ASCII ist beispielsweise immer noch eine legitime (7-Bit) Unicode-Kodierung.

Es wurde vorgeschlagen, dass es ein Modul geben sollte, das Surrogate in schmalen Python-Builds für Programmierer handhabt. Wenn jemand dies implementieren möchte, wird dies ein weiterer PEP sein. Es könnte auch mit Funktionen kombiniert werden, die andere Arten von Zeichen-, Wort- und Zeilen-basierten Indizierungen ermöglichen.

Abgelehnte Vorschläge

Mehr oder weniger der Status quo

Wir könnten offiziell sagen, dass Python-Zeichen 16-Bit sind und Programmierer auffordern, breite Zeichen in ihrer Anwendungslogik durch die Kombination von Surrogat-Paaren zu implementieren. Dies ist eine hohe Belastung, da die Emulation von 32-Bit-Zeichen, wenn sie vollständig in Python kodiert ist, wahrscheinlich sehr ineffizient ist. Außerdem wären diese abstrahierten Pseudo-Strings nicht als Eingabe für die reguläre Ausdrucks-Engine gültig.

„Speichereffizienter Unicode“-Typ

Eine andere Lösungsklasse besteht darin, eine effiziente interne Speicherung zu verwenden, dem Programmierer aber eine Abstraktion von breiten Zeichen zu präsentieren. Jede dieser Lösungen würde eine wesentlich komplexere Implementierung erfordern als die akzeptierte Lösung. Betrachten Sie zum Beispiel die Auswirkungen auf die reguläre Ausdrucks-Engine. Theoretisch könnten wir zu dieser Implementierung in der Zukunft wechseln, ohne Python-Code zu brechen. Ein zukünftiges Python könnte breite Python-Semantik auf schmalem Python „emulieren“. Guido ist derzeit nicht bereit, die Implementierung durchzuführen.

Zwei Typen

Wir könnten neben dem 16-Bit-Typ einen 32-Bit-Unicode-Typ einführen. Es gibt viel Code, der erwartet, dass es nur einen einzigen Unicode-Typ gibt.

Dieser PEP stellt die Lösung mit dem geringsten Aufwand dar. In den nächsten Jahren werden 32-Bit-Unicode-Zeichen häufiger vorkommen, was uns entweder davon überzeugen kann, dass wir eine ausgefeiltere Lösung benötigen, oder (andererseits) uns davon überzeugt, dass die einfache Mandatierung breiter Unicode-Zeichen eine geeignete Lösung ist. Derzeit sind die beiden auf dem Tisch liegenden Optionen: nichts tun oder dies tun.

Referenzen

Unicode-Glossar: http://www.unicode.org/glossary/


Quelle: https://github.com/python/peps/blob/main/peps/pep-0261.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT