Heim > Java > javaLernprogramm > Detaillierte Einführung in einige Dinge im Zusammenhang mit Codepoint und UTF-16 in Java

Detaillierte Einführung in einige Dinge im Zusammenhang mit Codepoint und UTF-16 in Java

黄舟
Freigeben: 2017-03-21 11:11:40
Original
1541 Leute haben es durchsucht

Die Beziehung zwischen Unicode und UTF-8/UTF-16/UTF-32

Die Beziehung zwischen Unicode und UTF-8/UTF-16/UTF-32 ist der Zeichensatz und Kodierungsbeziehung. Das Konzept des Zeichensatzes umfasst tatsächlich zwei Aspekte: Der eine ist der Zeichensatz und der andere das Codierungsschema. Ein Zeichensatz definiert alle darin enthaltenen Symbole. Ein Zeichensatz im engeren Sinne umfasst kein Kodierungsschema. Er definiert lediglich alle Symbole, die zu diesem Zeichensatz gehören. Aber im Allgemeinen definiert ein Zeichensatz nicht nur eine Sammlung von Zeichen, sondern auch eine binäre Kodierung für jedes Symbol. Wenn wir GB2312 oder ASCII erwähnen, bedeutet dies implizit, dass das Codierungsschema GB2312 oder ASCII ist. In diesen Fällen können Zeichensatz und Codierungsschema als gleich angesehen werden.

Aber Unicode verfügt über mehrere Codierungsschemata. Das durch den Unicode-Zeichensatz festgelegte Standardkodierungsschema ist UCS-2 (UTF-16), das zwei Bytes zur Darstellung eines Unicode-Zeichens verwendet (zwei Bytes in UTF-16 sind grundlegende mehrsprachige flache Zeichen, 4 Bytes). sind Hilfsebenenzeichen). UCS-4 (UTF-32) verwendet 4 Bytes zur Darstellung eines Unicode-Zeichens. Ein weiteres häufig verwendetes Unicode-Codierungsschema – UTF-8 – verwendet 1 bis 4 Bytes variabler Länge zur Darstellung eines Unicode-Zeichens und kann über einen einfachen Konvertierungsalgorithmus direkt aus UTF-16 abgerufen werden. Daher gibt es bei der Verwendung des Unicode-Zeichensatzes mehrere Kodierungsschemata, die in entsprechenden Szenarien verwendet werden.

Einfacher ausgedrückt entspricht der Unicode-Zeichensatz einem Wörterbuch, das alle Zeichen (d. h. Bilder) und ihre entsprechenden Unicode-Codes (unabhängig vom spezifischen Codierungsschema), UTF-8/UTF-, aufzeichnet. 16/UTF-32-Code sind die Daten, die durch Unicode-Code über entsprechende Formeln berechnet und tatsächlich gespeichert und übertragen werden.

UTF-16

Die JVM-Spezifikation besagt eindeutig, dass das vom Java-Char-Typ verwendete Codierungsschema UTF-16 ist. Lassen Sie uns also zunächst UTF-16 verstehen.

Der Kodierungsraum von Unicode reicht von U+0000 bis U+10FFFF. Es gibt 1112064 Codepunkte, die zum Zuordnen von Zeichen verwendet werden können. Dieser Teil des Codierungsraums kann in 17 Ebenen unterteilt werden, wobei jede Ebene 2^16 (65536) Codebits enthält. Die erste Ebene wird als Basic Multilingual Plane (BMP) oder Ebene 0 bezeichnet. Andere Flugzeuge werden Ergänzungsflugzeuge genannt. In der grundlegenden mehrsprachigen Ebene sind die Codepunktblöcke von U+D800 bis U+DFFF dauerhaft reserviert und werden nicht auf Unicode-Zeichen abgebildet. UTF-16 verwendet die reservierten Codebits des Abschnitts 0xD800-0xDFFF, um die Codebits der Hilfsebenenzeichen zu codieren.

Die am häufigsten verwendeten Zeichen sind in BMP enthalten und werden durch 2 Bytes dargestellt. Die Codebits in der Hilfsebene werden in ein Paar 16 Bit langer Codeelemente in UTF-16 codiert, ein sogenanntes Ersatzpaar. Die spezifische Methode ist:

  • Subtrahieren Sie 0×10000 aus dem Codebit, und der resultierende Wert reicht von 0 bis 0xFFFFF, was 20 Bits lang ist.

  • Der hohe 10-Bit-Wert (der Wertebereich ist 0 ~ 0x3FF) wird zu 0xD800 addiert, um das erste Codeelement zu erhalten, oder als hoher Ersatzwert bezeichnet. Der Wertebereich beträgt 0xD800 ~ 0xDBFF. Da der Wert des Proxys höherer Ordnung kleiner ist als der des Proxys niedriger Ordnung, nennt der Unicode-Standard jetzt die Lead-Surrogate des Proxys höherer Ordnung.

  • Der niedrige 10-Bit-Wert (der Wertebereich ist ebenfalls 0 ~ 0x3FF) wird zu 0xDC00 addiert, um das zweite Codeelement zu erhalten, oder als niedriger Ersatzwert bezeichnet. Der aktuelle Wert ist Der Bereich ist 0xDC00~0xDFFF. Da das Ersatzzeichen niedriger Ordnung einen größeren Wert hat als das Ersatzzeichen hoher Ordnung, nennt der Unicode-Standard jetzt die Ersatzzeichen niedriger Ordnung als Ersatzzeichen.

Zum Beispiel U+10437-Kodierung:

  • 0×10437 minus 0×10000, das Ergebnis ist 0×00437, was binär ist ist 0000 0000 0100 0011 0111.

  • Partitionieren Sie den oberen 10-Bit-Wert und den unteren 10-Bit-Wert (mit Binärwert): 0000000001 und 0000110111.

  • Addieren Sie 0xD800 zum oberen Wert, um das High-Bit zu bilden: 0xD800 + 0×0001 = 0xD801.

  • Addieren Sie 0xDC00 zum unteren Wert, um das Low-Bit zu bilden: 0xDC00 + 0×0037 = 0xDC37.

Da sich die Codepunkte des führenden Agenten, des nachfolgenden Agenten und der gültigen Zeichen in BMP nicht überschneiden, ist es unmöglich, dass ein Teil einer Zeichenkodierung gleich ist als weitere Zeichenkodierung bei der Suche. Verschiedene Teile überlappen sich. Sie können also das Startcodeelement des nächsten Zeichens für ein bestimmtes Zeichen bestimmen, indem Sie nur ein Codeelement untersuchen (die Grundeinheit, aus der ein Codepunkt besteht, 2 Bytes).

Codepoint bezogen auf Java

Für ein String-Objekt wird sein Inhalt über ein char-Array gespeichert. Der char-Typ wird in 2 Bytes gespeichert, und diese 2 Bytes speichern tatsächlich die Codeelemente unter UTF-16-Codierung. Wenn wir die Methoden charAt und length verwenden, werden tatsächlich ein Codeelement und die Anzahl der Codeelemente zurückgegeben. Obwohl es im Allgemeinen kein Problem gibt, erhalten die beiden oben genannten Methoden nicht das richtige Ergebnis, wenn es sich bei dem Zeichen um ein Hilfsebenenzeichen handelt . Die korrekte Verarbeitungsmethode lautet wie folgt:

int character = aString.codePointAt(i);
int length = aString.codePointCount(0, aString.length());
Nach dem Login kopieren

Es ist zu beachten, dass der Rückgabewert von codePointAt int statt char ist. Dieser Wert ist der Unicode-Code.

codePointAt-Methode ruft codePointAtImpl auf:

static int codePointAtImpl(char[] a, int index, int limit) {
        char c1 = a[index];
        if (isHighSurrogate(c1) && ++index < limit) {
            char c2 = a[index];
            if (isLowSurrogate(c2)) {
                return toCodePoint(c1, c2);
            }
        }
        return c1;
    }
Nach dem Login kopieren

isHighSurrogate-Methode bestimmt, ob die 2 Bytes des tiefgestellten Zeichens führende Ersatzzeichen in UTF-16 (0xD800~0xDBFF) sind:

public static boolean isHighSurrogate(char ch) {
        // Help VM constant-fold; MAX_HIGH_SURROGATE + 1 == MIN_LOW_SURROGATE
        return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1);
    }
Nach dem Login kopieren
public static final char MIN_HIGH_SURROGATE = &#39;\uD800&#39;;
public static final char MAX_HIGH_SURROGATE = &#39;\uDBFF&#39;;
Nach dem Login kopieren

然后++index,isLowSurrogate方法判断下一个字符的2个字节是否为后尾代理(0xDC00~0xDFFF):

public static boolean isLowSurrogate(char ch) {
        return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1);
    }
Nach dem Login kopieren
public static final char MIN_LOW_SURROGATE  = &#39;\uDC00&#39;;
public static final char MAX_LOW_SURROGATE  = &#39;\uDFFF&#39;;
Nach dem Login kopieren

toCodePoint方法将这2个码元组装成一个Unicode码:

public static int toCodePoint(char high, char low) {
        // Optimized form of:
        // return ((high - MIN_HIGH_SURROGATE) << 10)
        //         + (low - MIN_LOW_SURROGATE)
        //         + MIN_SUPPLEMENTARY_CODE_POINT;
        return ((high << 10) + low) + (MIN_SUPPLEMENTARY_CODE_POINT
                                       - (MIN_HIGH_SURROGATE << 10)
                                       - MIN_LOW_SURROGATE);
    }
Nach dem Login kopieren

这个过程就是以上将一个辅助平面的Unicode码位转换成2个码元的逆过程。

所以,枚举字符串的正确方法:

for (int i = 0; i < aString.length();) {
	int character = aString.codePointAt(i);
	//如果是辅助平面字符,则i+2
	if (Character.isSupplementaryCodePoint(character)) i += 2;
	else ++i;
}
Nach dem Login kopieren

将codePoint转换为char[]可调用Character.toChars方法,然后可进一步转换为字符串:

new String(Character.toChars(codePoint));
Nach dem Login kopieren

toChars方法所做的就是以上将Unicode码位转换为2个码元的过程。

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in einige Dinge im Zusammenhang mit Codepoint und UTF-16 in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage