J'ai un examen de programmation universitaire à venir, et une section est sur l'unicode.
J'ai vérifié partout pour trouver des réponses à cette question, et mon conférencier est inutile, donc ce n'est pas utile, c'est donc un dernier recours pour vous les gars.
La question sera quelque chose comme:
La chaîne 'mЖ 丽' a ces points de code unicode
U+006D
,U+0416
etU+4E3D
, avec des réponses écrites en hexadécimal, encodez manuellement la chaîne en UTF-8 et UTF-16.
Toute aide sera grandement appréciée alors que j'essaie de comprendre ce problème.
Sensationnel. D'une part, je suis ravi de savoir que les cours universitaires enseignent à la réalité que les encodages de caractères sont un travail difficile, mais en fait, connaître les règles de codage UTF-8 semble attendre beaucoup. (Cela aidera-t-il les étudiants réussir le test de la Turquie ?)
La description la plus claire que j'ai vue jusqu'à présent pour les règles de codage des points de code UCS en UTF-8 provient 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 de se souvenir d'une version "compressée" du graphique:
Les octets initiaux démarrent des points de code déformés commencent par un 1
, et ajoutez un rembourrage 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 plages 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 [~ # ~] i [~ # ~] je me souviens des règles pour dériver le graphique plus facilement que le graphique lui-même. Nous espérons également que vous vous souvenez bien des règles. :)
Mise à jour
Une fois que vous avez construit le graphique ci-dessus, vous pouvez convertir les points de code Unicode d'entrée en UTF-8 en trouvant leur plage, en convertissant de l'hexadécimal en binaire, en insérant les bits selon les règles ci-dessus, puis en les reconvertissant en hex:
U+4E3E
Cela s'inscrit dans le 0x00000800 - 0x0000FFFF
intervalle (0x4E3E < 0xFFFF
), donc 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 un x
au début, remplissez-le avec 0
:
11100100 10111000 10111110
Convertir de bits en hex :
0xE4 0xB8 0xBE
Les descriptions sur Wikipedia pour TF-8 et TF-16 sont bonnes:
Procédures pour votre exemple de chaîne:
UTF-8 utilise jusqu'à 4 octets pour représenter les points de code Unicode. Pour le cas à 1 octet, utilisez le modèle suivant:
UTF-8 1 octet = 0xxxxxxxpoubelle = 7 bits = 0-7Fhex
L'octet initial de 2, 3 et 4 octets UTF-8 commence par 2, 3 ou 4 bits un, suivi par un bit zéro. Les octets de suivi commencent toujours par le modèle à deux bits 10
, laissant 6 bits pour les données:
UTF-8 à 2 octets = 110xxxxx 10xxxxxxpoubelle = 5 + 6 (11) bits = 80-7FFhex
UTF-8 à 3 octets = 1110xxxx 10xxxxxx 10xxxxxxpoubelle = 4 + 6 + 6 (16) bits = 800-FFFFhex
UTF-8 à 4 octets = 11110xxx 10xxxxxx 10xxxxxx 10xxxxxxpoubelle = 3 + 6 + 6 + 6 (21) bits = 10000-10FFFFhex††Les points de code Unicode ne sont pas définis au-delà de 10FFFFhex.
Vos points de code sont U + 006D, U + 0416 et U + 4E3D nécessitant des séquences UTF-8 à 1, 2 et 3 octets, respectivement. Convertissez en binaire et assignez les bits:
U + 006D = 1101101poubelle = 1101101poubelle = 6Dhex
U + 0416 = 10000 010110poubelle = 11010000 dix010110poubelle = D0 96hex
U + 4E3D = 0100 111000 111101poubelle = 11100100 dix111000 dix111101poubelle = E4 B8 BDhex
Séquence d'octets finale:
6D D0 96 E4 B8 BD
ou si des chaînes terminées par nul sont souhaitées:
6D D0 96 E4 B8 BD 00
UTF-16 utilise 2 ou 4 octets pour représenter les points de code Unicode. Algorithme:
U + 0000 à U + D7FF utilise 0000 sur 2 octetshex à D7FFhex
U + D800 à U + DFFF sont des points de code non valides réservés pour UTF-16 à 4 octets
U + E000 à U + FFFF utilise E000 sur 2 octetshex à FFFFhexU + 10000 à U + 10FFFF utilise un UTF-16 à 4 octets codé comme suit:
- Soustraire 10000hex du point de code.
- Résultat express sous forme de binaire 20 bits.
- Utilisez le modèle 110110xxxxxxxxxx 110111xxxxxxxxxxpoubelle pour coder les 10 bits supérieur et inférieur en deux mots de 16 bits.
Utilisation de vos points de code:
U + 006D = 006Dhex
U + 0416 = 0416hex
U + 4E3D = 4E3Dhex
Maintenant, nous avons un autre problème. Certaines machines stockent d'abord les deux octets d'un octet de poids faible de Word 16 bits (machines dites little-endian) et certaines stockent l'octet de poids fort en premier (machines big-endian). UTF-16 utilise le point de code U + FEFF (appelé la marque d'ordre des octets ou BOM) pour aider une machine à déterminer si un flux d'octets contient du UTF-16 à gros ou petit bout:
big-endian = FE FF 00 6D 04 16 4E 3D
petit-boutien = FF FE 6D 00 16 04 3D 4E
Avec nul-terminaison, U + 0000 = 0000hex:
big-endian = FE FF 00 6D 04 16 4E 3D 00 00
petit-boutien = FF FE 6D 00 16 04 3D 4E 00 00
Étant donné que votre instructeur n'a pas donné de point de code nécessitant un UTF-16 à 4 octets, voici un exemple:
U + 1F031 = 1F031hex - 10000hex = F031hex = 0000111100 0000110001poubelle =
1101100000111100 1101110000110001poubelle = D83C DC31hex
Le programme suivant fera le travail nécessaire. Il n'est peut-être pas suffisamment "manuel" pour vos besoins, mais vous pouvez au moins 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";