Conversion manuelle des codépoints unicode en UTF-8 et UTF-16

j'ai un examen de programmation universitaire qui arrive, et une section est sur unicode.

j'ai vérifié partout pour des réponses à cela, et mon conférencier est inutile si ce n'est pas une aide, donc c'est un dernier recours pour vous les gars pour éventuellement aider.

la question sera quelque chose comme:

la chaîne de caractères "mж?" a ces codépoints unicode U+006D , U+0416 et U+4E3D , avec les réponses écrites en hexadécimal, encoder manuellement les chaîne en UTF-8 et UTF-16.

N'importe quelle aide du tout sera grandement apprécié comme j'essaye d'obtenir ma tête autour de ceci.

29
demandé sur JakeGould 2011-06-05 03:41:24

3 réponses

Wow. D'une part, je suis ravie de savoir que les cours universitaires enseignent à la réalité que l'encodage de caractères est un travail difficile, mais en fait, connaître les règles D'encodage UTF-8 semble beaucoup attendre. (Aidera-t-il les étudiants passer le test de la Turquie ?)

la description la plus claire que j'ai vu jusqu'à présent pour les règles d'encodage UCS codepoints à UTF-8 sont de la page de manuel utf-8(7) sur de nombreux systèmes Linux:

Encoding
   The following byte sequences are used to represent a
   character.  The sequence to be used depends on the UCS code
   number of the character:

   0x00000000 - 0x0000007F:
       0xxxxxxx

   0x00000080 - 0x000007FF:
       110xxxxx 10xxxxxx

   0x00000800 - 0x0000FFFF:
       1110xxxx 10xxxxxx 10xxxxxx

   0x00010000 - 0x001FFFFF:
       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

   [... removed obsolete five and six byte forms ...]

   The xxx bit positions are filled with the bits of the
   character code number in binary representation.  Only the
   shortest possible multibyte sequence which can represent the
   code number of the character can be used.

   The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well
   as 0xfffe and 0xffff (UCS noncharacters) should not appear in
   conforming UTF-8 streams.

Il pourrait être plus facile à retenir un "comprimé" version " de la carte:

les premiers octets des codépoints endommagés commencent par un 1 , et ajoutent le remplissage 1+0 . Les octets suivants commencent 10 .

0x80      5 bits, one byte
0x800     4 bits, two bytes
0x10000   3 bits, three bytes

vous pouvez dériver les gammes en prenant note de combien espace vous pouvez remplir avec les bits autorisés dans la nouvelle représentation:

2**(5+1*6) == 2048       == 0x800
2**(4+2*6) == 65536      == 0x10000
2**(3+3*6) == 2097152    == 0x200000

je sais je pourrait rappeler les règles de dériver le graphique plus facile que le tableau lui-même. J'espère que tu te souviens des règles aussi. :)

mise à Jour

une fois que vous avez construit le graphique ci-dessus, vous pouvez convertir les codépoints D'entrée Unicode en UTF-8 en trouvant leur portée, en passant de l'hexadécimal au binaire, en insérant les bits selon les règles ci-dessus, puis en convertissant de nouveau en hex:

U+4E3E

cela correspond à la gamme 0x00000800 - 0x0000FFFF ( 0x4E3E < 0xFFFF ), de sorte que la représentation sera de la forme:

   1110xxxx 10xxxxxx 10xxxxxx

0x4E3E est 100111000111110b . Déposez les bits dans le x ci-dessus (commencez par la droite, nous remplirons les bits manquants au début avec 0 ):

   1110x100 10111000 10111110

il reste une place x au départ, remplissez-la avec 0 :

   11100100 10111000 10111110

Convertir bits hex :

   0xE4 0xB8 0xBE
40
répondu sarnold 2017-12-12 01:44:42

les descriptions sur Wikipedia pour UTF-8 et UTF-16 sont bonnes:

procédures pour votre chaîne d'exemple:

UTF-8

UTF-8 utilise jusqu'à 4 octets pour représenter les codépoints Unicode. Pour le cas de 1 octet, utilisez le modèle suivant:

1-byte UTF-8 = 0xxxxxxx bin = 7 bits = 0-7F hex

le premier octet de 2, 3 et 4 octets UTF-8 commence avec 2, 3 ou 4 bits, suivi d'un bit zéro. Les octets suivants commencent toujours par le motif à deux bits 10 , laissant 6 bits pour les données:

2-byte UTF-8 = 110xxxxx 10xxxxxx bin = 5+6(11) bits = 80-7FF hex

3-byte UTF-8 = 1110xxxx 10xxxxxx 10xxxxxx bin = 4+6+6(16) bits = 800-FFFF hex

4-byte UTF-8 = 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx bin = 3+6+6+6(21) bits = 10000-10FFFF hex

les codépoints Unicode ne sont pas définis au-delà de 10FF hex .

vos codépoints sont U+006D, U+0416 et U+4E3D nécessitant respectivement des séquences UTF-8 de 1, 2 et 3 octets. Convertissez en binaire et assignez les bits:

U+006D = 1101101 bin = 0 1101101 bin = 6D hex

U+0416 = 10000 010110 bin = 110 10000 10 010110 bin = D0 96 hex

U+4E3D = 0100 111000 111101 bin = 1110 0100 10 111000 10 111101 bin = E4 B8 BD hex

Dernier octet de la séquence:

6D D0 96 E4 B8 BD

ou si nul chaînes terminées sont souhaitées:

6D D0 96 E4 B8 BD 00

UTF-16

UTF-16 utilise 2 ou 4 octets pour représenter les codépoints Unicode. Algorithme:

U+0000 à U+D7FF utilise 2 octets 0000 hex à D7FF hex

U+D800 à U+DFFF sont des codépoints invalides réservés pour 4 octets UTF-16

U+E000 à U+FFFF utilise 2 octets E000 hex FFFF hex

U+10000 à U+10FFF utilise 4 octets UTF-16 codé comme suit:

  1. soustrayez 10000 hex du codepoint.
  2. résultat Express en binaire 20 bits.
  3. utilisez le modèle 110110xxxxxxxxxxxxxx 110111xxxxxxxxxxxxxx bin pour coder les bits supérieur et inférieur en deux mots de 16 bits.

en utilisant vos codépoints:

U+006D = 006D hex

U+0416 = 0416 hex

U+4E3D = 4e3d hex

maintenant, nous avons un autre problème. Certains magasins de machines les deux octets d'un mot de 16 bits dont le premier octet est le moins significatif (ce qu'on appelle les machines little-endian) et d'autres dont le premier octet est le plus significatif (les machines big-endian). UTF-16 utilise le codepoint U+FEFF (appelé le byte order mark ou BOM) pour aider une machine à déterminer si un flux de byte contient un UTF - 16 big-ou little-endian:

big-endian = ff 00 6D 04 16 4E 3D
1519300920" little-endian = FF FE 6D 00 16 04 3D 4E

Avec les nuls-la résiliation, U+0000 = 0000 hex :

big-endian = ff 00 6D 04 16 4E 3D 00 00
1519300920" little-endian = FF FE 6D 00 16 04 3D 4E 00 00

étant donné que votre instructeur n'a pas donné de codépoint qui exigeait 4 octets UTF-16, Voici un exemple:

U+1F031 = 1f031 hex - 10000 hex = F031 hex = 0000111100 0000110001 bin =

110110 0000111100 110111 0000110001 bin = D83C DC31 hex

34
répondu Mark Tolonen 2014-05-14 00:51:37

le programme suivant fera le travail nécessaire. Il ne peut pas être "manuel" assez pour vos besoins, mais au minimum vous pouvez vérifier votre travail.

#!/usr/bin/perl

use 5.012;
use strict;
use utf8;
use autodie;
use warnings;
use warnings    qw< FATAL utf8 >;
no warnings     qw< uninitialized >;
use open        qw< :std :utf8 >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

my ($x) = "mЖ丽";

open(U8,">:encoding(utf8)","/tmp/utf8-out");
print U8 $x;
close(U8);
open(U16,">:encoding(utf16)","/tmp/utf16-out");
print U16 $x;
close(U16);
system("od -t x1 /tmp/utf8-out");
my $u8 = encode("utf-8",$x);
print "utf-8: 0x".unpack("H*",$u8)."\n";

system("od -t x1 /tmp/utf16-out");
my $u16 = encode("utf-16",$x);
print "utf-16: 0x".unpack("H*",$u16)."\n";
4
répondu Seth Robertson 2011-06-05 01:48:51