Wie erhalten Sie eine zuverlässige Anzahl von Unicode-Zeichen in Python?

8

Google App Engine verwendet Python 2.5.2, anscheinend mit UCS4 aktiviert. Aber der GAE-Datenspeicher verwendet intern UTF-8. Wenn Sie also u '\ ud834 \ udd0c' (Länge 2) im Datenspeicher speichern, erhalten Sie beim Abrufen '\ U0001d10c' (Länge 1). Ich versuche, die Anzahl der Unicode-Zeichen in der Zeichenfolge so zu zählen, dass vor und nach dem Speichern das gleiche Ergebnis erzielt wird. Also versuche ich, die Zeichenfolge (von u '\ ud834 \ udd0c' nach '\ U0001d10c') zu normalisieren, sobald ich sie erhalte, bevor ich ihre Länge berechne und sie in den Datenspeicher lege. Ich weiß, dass ich es einfach in UTF-8 kodieren und dann wieder dekodieren kann, aber gibt es einen einfacheren / effizienteren Weg?

    
Travis 03.08.2011, 06:26
quelle

2 Antworten

4
  

Ich weiß, ich kann es einfach in UTF-8 kodieren und dann wieder dekodieren

Ja, das ist das übliche Idiom, um das Problem zu beheben, wenn Sie "UTF-16-Surrogate in UCS-4 string" -Eingabe haben. Aber wie Mechanical snail sagte, ist diese Eingabe fehlerhaft und Sie sollten das korrigieren, was sie erzeugt hat.

  

Gibt es einen einfacheren / effizienteren Weg?

Nun ... du könntest das manuell mit einer Regex machen, wie:

%Vor%

Sicherlich nicht geradliniger ... Ich habe auch meine Zweifel, ob es tatsächlich effizienter ist!

    
bobince 03.08.2011, 14:41
quelle
2

Leider hängt das Verhalten des CPython-Interpreters in Versionen vor 3.3 davon ab, ob es mit "enger" oder "weiter" Unicode-Unterstützung gebaut wird. Daher kann der gleiche Code, beispielsweise ein Aufruf von len , in verschiedenen Builds des Standardinterpreters ein anderes Ergebnis haben. Beispiele dazu finden Sie diese Frage .

Die Unterscheidung zwischen "schmal" und "breit" besteht darin, dass "schmale" Interpreter intern 16-Bit-Code-Einheiten (UCS-2) speichern, während "breite" Interpreter intern 32-Bit-Code-Einheiten (UCS-4) speichern. Code Punkte U + 10000 und darüber (außerhalb der mehrsprachigen Basic-Ebene) haben einen len von zwei auf "schmalen" Interpretern, weil zwei UCS-2-Code -Einheiten benötigt werden um sie zu repräsentieren (mit Surrogaten), und das ist es, was len misst. Bei "Wide" -Builds wird nur ein einziger UCS-4-Code -Einheit für einen Nicht-BMP-Code Punkt benötigt. Für diese Builds ist also len eins für solche Codepunkte .

Ich habe bestätigt, dass der folgende Code alle unicode -Zeichenfolgen behandelt, unabhängig davon, ob sie Ersatzpaare enthalten oder nicht, und in CPython 2.7 sowohl für schmale als auch für breite Builds funktioniert. (Die Angabe eines Strings wie u'\ud83d\udc4d' in einem Wide-Interpreter spiegelt den ausdrücklichen Wunsch wider, einen vollständigen Ersatzcode Punkt im Unterschied zu einem Teilzeichencode Einheit darzustellen und zu sein daher nicht automatisch ein Fehler zu korrigieren, aber ich ignoriere das hier. Es ist ein Randfall und normalerweise kein gewünschter Anwendungsfall.)

Der Trick @invoke , der unten verwendet wird, ist eine Möglichkeit, wiederholte Berechnungen zu vermeiden, ohne etwas zum __dict__ des Moduls hinzuzufügen.

%Vor%     
wberry 30.03.2012 17:46
quelle