Différence entre UTF-8 et UTF-16?

137

Différence entre UTF-8 et UTF-16? Pourquoi en avons-nous besoin?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
theJava
la source
2
jon skeet a un bon article sur l'encodage .... csharpindepth.com/Articles/General/Unicode.aspx
Mitch Wheat

Réponses:

284

Je crois qu'il y a beaucoup de bons articles à ce sujet sur le Web, mais voici un bref résumé.

UTF-8 et UTF-16 sont des codages de longueur variable. Cependant, en UTF-8, un caractère peut occuper un minimum de 8 bits, tandis qu'en UTF-16, la longueur des caractères commence par 16 bits.

Principaux avantages de l'UTF-8:

  • Les caractères ASCII de base comme les chiffres, les caractères latins sans accents, etc. occupent un octet qui est identique à la représentation US-ASCII. De cette façon, toutes les chaînes US-ASCII deviennent UTF-8 valides, ce qui offre une compatibilité descendante décente dans de nombreux cas.
  • Pas d'octets nuls, ce qui permet d'utiliser des chaînes terminées par null, cela introduit également une grande compatibilité ascendante.
  • UTF-8 est indépendant de l'ordre des octets, vous n'avez donc pas à vous soucier du problème Big Endian / Little Endian.

Principaux inconvénients de l'UTF-8:

  • De nombreux caractères communs ont des longueurs différentes, ce qui ralentit l'indexation par point de code et calcule terriblement le nombre de points de code.
  • Même si l'ordre des octets n'a pas d'importance, parfois UTF-8 a toujours BOM (marque d'ordre d'octet) qui sert à notifier que le texte est encodé en UTF-8, et rompt également la compatibilité avec le logiciel ASCII même si le texte ne contient que des caractères ASCII . Les logiciels Microsoft (comme Notepad) aiment particulièrement ajouter une nomenclature à UTF-8.

Principaux avantages de l'UTF-16:

  • Caractères BMP (plan multilingue de base), y compris le latin, le cyrillique, la plupart des chinois (la PRC a rendu obligatoire la prise en charge de certains points de code en dehors de BMP), la plupart des japonais peuvent être représentés avec 2 octets. Cela accélère l'indexation et le calcul du nombre de points de code au cas où le texte ne contiendrait pas de caractères supplémentaires.
  • Même si le texte a des caractères supplémentaires, ils sont toujours représentés par des paires de valeurs 16 bits, ce qui signifie que la longueur totale est toujours divisible par deux et permet d'utiliser 16 bits charcomme composant primitif de la chaîne.

Principaux inconvénients de l'UTF-16:

  • Beaucoup d'octets nuls dans les chaînes US-ASCII, ce qui signifie qu'il n'y a pas de chaînes terminées par null et beaucoup de mémoire gaspillée.
  • Son utilisation comme encodage à longueur fixe «fonctionne principalement» dans de nombreux scénarios courants (en particulier aux États-Unis / dans l'UE / dans les pays avec des alphabets cyrilliques / Israël / les pays arabes / l'Iran et bien d'autres), conduisant souvent à un support cassé là où ce n'est pas le cas. Cela signifie que les programmeurs doivent être conscients des paires de substitution et les gérer correctement dans les cas où cela compte!
  • C'est de longueur variable, donc compter ou indexer les points de code est coûteux, bien que moins que UTF-8.

En général, UTF-16 est généralement meilleur pour la représentation en mémoire car BE / LE n'y est pas pertinent (utilisez simplement l'ordre natif) et l'indexation est plus rapide (n'oubliez pas de gérer correctement les paires de substitution). UTF-8, d'autre part, est extrêmement bon pour les fichiers texte et les protocoles réseau car il n'y a pas de problème BE / LE et la terminaison nulle est souvent pratique, ainsi que la compatibilité ASCII.

Sergueï Tachenov
la source
3
Manque uniquement la partie BE / LE sur UTF16 :) UTF-8 a un autre inconvénient, il peut générer une sortie plus longue que UTF16
bestsss
4
Oui, j'ai oublié BE / LE. Ce n'est pas un gros problème, cependant, en particulier pour une utilisation en mémoire. UTF-8 générera une sortie plus longue uniquement si des caractères à trois octets sont impliqués, mais cela signifie principalement le chinois et le japonais. D'un autre côté, si le texte contient beaucoup de caractères US-ASCII, il peut générer une sortie plus courte, donc si c'est un inconvénient ou non dépend d'une situation particulière.
Sergei Tachenov
Je n'ai même pas pensé à mentionner le pro immédiat de l'utf-8, plus court. À propos de la sortie plus longue de utf-8, il était «peut» pour une raison, mais si la cible est à l'extrême est, l'encodage par défaut devrait être utf-16. Comme pour l'exemple md.update (text.getBytes ("UTF-8")); l'encodage n'a pas d'importance puisque le hachage est stable dans les deux sens.
bestsss
Le moyen le plus rapide de convertir une chaîne en tableau d'octets est quelque chose comme ça, publié comme exemple
bestsss
Vous dites que les caractères ont une longueur différente en UTF-8, donc cela ralentit l'indexation et le calcul de la longueur, mais je doute que les caractères en UTF-16 aient également une longueur différente, l'indexation et le calcul de la longueur de UTF-16 devraient-ils être plus rapides?
nicky_zs
19

Ce sont simplement des schémas différents pour représenter les caractères Unicode.

Les deux sont de longueur variable - UTF-16 utilise 2 octets pour tous les caractères du plan multilingue de base (BMP) qui contient la plupart des caractères d'usage courant.

UTF-8 utilise entre 1 et 3 octets pour les caractères dans le BMP, jusqu'à 4 pour les caractères de la plage Unicode actuelle de U + 0000 à U + 1FFFFF, et est extensible jusqu'à U + 7FFFFFFF si cela devient nécessaire ... mais notamment tous les caractères ASCII sont représentés chacun dans un seul octet.

Pour les besoins d'un résumé de message, peu importe lequel de ceux que vous choisissez, tant que tous ceux qui essaient de recréer le résumé utilisent la même option.

Consultez cette page pour en savoir plus sur UTF-8 et Unicode.

(Notez que tous les caractères Java sont des points de code UTF-16 dans le BMP; pour représenter les caractères au-dessus de U + FFFF, vous devez utiliser des paires de substitution en Java.)

Jon Skeet
la source
5

Sécurité: utilisez uniquement UTF-8

Différence entre UTF-8 et UTF-16? Pourquoi en avons-nous besoin?

Il y a eu au moins quelques vulnérabilités de sécurité dans les implémentations de UTF-16 . Voir Wikipedia pour plus de détails .

WHATWG et W3C ont maintenant déclaré que seul UTF-8 doit être utilisé sur le Web.

Les problèmes de [sécurité] décrits ici disparaissent lorsque l'on utilise exclusivement UTF-8, ce qui est l'une des nombreuses raisons qui sont maintenant le codage obligatoire pour toutes choses.

D'autres groupes disent la même chose.

Ainsi, bien que l'UTF-16 puisse continuer à être utilisé en interne par certains systèmes tels que Java et Windows, le peu d'utilisation de l'UTF-16 que vous avez pu voir dans le passé pour les fichiers de données, l'échange de données, etc., disparaîtra probablement complètement.

Basil Bourque
la source
4

Ceci n'est pas lié à UTF-8/16 (en général, bien qu'il soit converti en UTF16 et que la partie BE / LE puisse être définie avec une seule ligne), voici le moyen le plus rapide de convertir une chaîne en octet []. Par exemple: bon exactement pour le cas fourni (code de hachage). String.getBytes (enc) est relativement lent.

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }
bestsss
la source
-3

Un moyen simple de différencier UTF-8 et UTF-16 est d'identifier les points communs entre eux.

Outre le partage du même numéro Unicode pour un caractère donné, chacun est son propre format.

Venkateswara Rao
la source