Maison  >  Article  >  Java  >  Introduction détaillée à certaines choses liées au point de code et à UTF-16 en Java

Introduction détaillée à certaines choses liées au point de code et à UTF-16 en Java

黄舟
黄舟original
2017-03-21 11:11:401539parcourir

La relation entre Unicode et UTF-8/UTF-16/UTF-32

La relation entre Unicode et UTF-8/UTF-16/UTF-32 est le jeu de caractères et relation d'encodage. Le concept de jeu de caractères comprend en fait deux aspects : l’un est le jeu de caractères et l’autre est le schéma de codage. Un jeu de caractères définit tous les symboles qu'il contient. Un jeu de caractères au sens étroit n'inclut pas de schéma de codage. Il définit simplement tous les symboles qui appartiennent à ce jeu de caractères. Mais d’une manière générale, un jeu de caractères ne définit pas seulement une collection de caractères, il définit également un codage binaire pour chaque symbole. Lorsque nous mentionnons GB2312 ou ASCII, cela indique implicitement que le schéma de codage est GB2312 ou ASCII. Dans ces cas, le jeu de caractères et le schéma de codage peuvent être considérés comme égaux.

Mais Unicode a plusieurs schémas de codage. Le schéma de codage standard spécifié par le jeu de caractères Unicode est UCS-2 (UTF-16), qui utilise deux octets pour représenter un caractère Unicode (deux octets en UTF-16 sont des caractères plats de base multilingues , 4 octets sont des caractères de plan auxiliaire). UCS-4 (UTF-32) utilise 4 octets pour représenter un caractère Unicode. Un autre schéma de codage Unicode couramment utilisé : UTF-8 utilise 1 à 4 octets de longueur variable pour représenter un caractère Unicode et peut être obtenu directement à partir d'UTF-16 à partir d'un simple algorithme de conversion. Par conséquent, il existe plusieurs schémas de codage lors de l'utilisation du jeu de caractères Unicode, qui sont utilisés dans les scénarios appropriés.

Pour le dire plus simplement, le jeu de caractères Unicode est équivalent à un dictionnaire, qui enregistre tous les caractères (c'est-à-dire les images) et leurs codes Unicode correspondants (quel que soit le schéma de codage spécifique), UTF-8/ UTF- Le code 16/UTF-32 correspond aux données calculées par le code Unicode via les formules correspondantes et réellement stockées et transmises.

UTF-16

La spécification JVM indique clairement que le schéma de codage utilisé par le type char de Java est UTF-16, comprenons donc d'abord UTF-16.

L'espace de codage d'Unicode va de U 0000 à U 10FFFF. Il existe 1112064 points de code (points de code) qui peuvent être utilisés pour mapper des caractères. Cette partie de l'espace de codage peut être divisée en 17 plans, chaque plan contenant 2 ^ 16 (65 536) bits de code. Le premier plan est appelé plan multilingue de base (BMP), ou plan 0. D’autres avions sont appelés avions supplémentaires. Dans le plan multilingue de base, les blocs de points de code de U D800 à U DFFF sont réservés en permanence et ne correspondent pas aux caractères Unicode. UTF-16 utilise les bits de code réservés de la section 0xD800-0xDFFF pour coder les bits de code des caractères du plan auxiliaire.

Les caractères les plus couramment utilisés sont inclus dans BMP et sont représentés par 2 octets. Les bits de code dans le plan auxiliaire sont codés dans une paire d'éléments de code de 16 bits de long en UTF-16, appelée paire de substitution. La méthode spécifique est la suivante :

  • Soustraire 0×10000. à partir du bit de code, et la valeur résultante est comprise entre 0 et 0xFFFFF, soit une longueur de 20 bits.

  • La valeur haute de 10 bits (la plage de valeurs est 0~0x3FF) est ajoutée à 0xD800 pour obtenir le premier élément de code ou appelée le substitut haut, la plage de valeurs est 0xD800~ 0xDBFF Étant donné que la valeur du proxy d'ordre supérieur est inférieure à celle du proxy d'ordre inférieur, afin d'éviter toute confusion, la norme Unicode appelle désormais les substituts principaux du proxy d'ordre supérieur.

  • La valeur faible de 10 bits (la plage de valeurs est également de 0 à 0x3FF) est ajoutée à 0xDC00 pour obtenir le deuxième élément de code ou appelée le substitut faible. La valeur actuelle est la plage. est 0xDC00~0xDFFF Étant donné que le substitut d'ordre inférieur a une valeur plus grande que le substitut d'ordre élevé, afin d'éviter toute confusion, la norme Unicode appelle désormais les substituts de piste de substitution d'ordre inférieur.

Par exemple, encodage U 10437 :

  • 0×10437 moins 0×10000, le résultat est 0×00437, ce qui en binaire est 0000 0000 0100 0011 0111.

  • Partitionnez sa valeur supérieure de 10 bits et sa valeur inférieure de 10 bits (en utilisant le binaire) : 0000000001 et 0000110111.

  • Ajoutez 0xD800 à la valeur supérieure pour former le bit haut : 0xD800 0×0001 = 0xD801.

  • Ajoutez 0xDC00 à la valeur inférieure pour former le bit faible : 0xDC00 0×0037 = 0xDC37.

Étant donné que les points de code de l'agent principal, de l'agent final et des caractères valides dans BMP ne se chevauchent pas, il est impossible qu'une partie d'un codage de caractère soit la même. comme autre codage de caractères lors de la recherche. Différentes parties se chevauchent. Vous pouvez donc déterminer l'élément de code de départ du caractère suivant pour un caractère donné en examinant un seul élément de code (l'unité de base qui constitue un point de code, 2 octets).

Codepoint lié en java

Pour un objet chaîne, son contenu est stocké via un tableau de caractères. Le type char est stocké sur 2 octets, et ces 2 octets stockent en fait les éléments de code sous encodage UTF-16. Lorsque nous utilisons les méthodes charAt et length, ce qui est réellement renvoyé est un élément de code et le nombre d'éléments de code. Bien qu'il n'y ait généralement aucun problème, si le caractère est un caractère de plan auxiliaire, les deux méthodes ci-dessus n'obtiendront pas le résultat correct. . La méthode de traitement correcte est la suivante :

int character = aString.codePointAt(i);
int length = aString.codePointCount(0, aString.length());

Il convient de noter que la valeur de retour de codePointAt est un int au lieu de char. Cette valeur est le code Unicode.

La méthode codePointAt appelle codePointAtImpl :

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;
    }

La méthode isHighSurrogate détermine si les 2 octets du caractère indice sont des substituts de début en UTF-16 (0xD800~0xDBFF) :

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);
    }
public static final char MIN_HIGH_SURROGATE = &#39;\uD800&#39;;
public static final char MAX_HIGH_SURROGATE = &#39;\uDBFF&#39;;

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

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

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);
    }

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

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

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

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

new String(Character.toChars(codePoint));

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn