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
etU+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.
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
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 hexU+10000 à U+10FFF utilise 4 octets UTF-16 codé comme suit:
- soustrayez 10000 hex du codepoint.
- résultat Express en binaire 20 bits.
- 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
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";