大学でのプログラミング試験が予定されていますが、1つはユニコードに関するセクションです。
私はこれに対する答えを全面的にチェックしました、そして私の講師は役に立たないので、それは助けにはなりません。
質問は次のようになります。
文字列 'mЖ丽'にはこれらのUnicodeコードポイントがあります
U+006D
、U+0416
およびU+4E3D
は、16進数で記述された回答とともに、文字列をUTF-8およびUTF-16に手動でエンコードします。
私はこれを回避しようとしているので、どんな助けでも大歓迎です。
ワオ。一方では、大学のコースが文字エンコーディングが大変な仕事であるという現実を教えていることを知ってワクワクしていますが、実際にはUTF-8エンコーディングルールを知っていることは多くのことを期待しているように聞こえます。 (学生を助ける トルコテストに合格 ?)
UCSコードポイントをUTF-8にエンコードするルールについてこれまで見てきた最も明確な説明は、多くのLinuxシステムのutf-8(7)
マンページにあります。
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.
チャートの「圧縮」バージョンを思い出す方が簡単かもしれません:
マングルされたコードポイントの最初のバイトの開始は1
で始まり、パディング1+0
を追加します。後続のバイトは10
で始まります。
0x80 5 bits, one byte
0x800 4 bits, two bytes
0x10000 3 bits, three bytes
新しい表現で許可されているビットで埋めることができるspaceの量に注意することで、範囲を導出できます。
2**(5+1*6) == 2048 == 0x800
2**(4+2*6) == 65536 == 0x10000
2**(3+3*6) == 2097152 == 0x200000
[〜#〜] i [〜#〜]は、チャート自体よりも簡単にチャートを導き出すためのルールを覚えていることを知っています。ルールを覚えるのが上手であることを願っています。 :)
更新
上記のチャートを作成したら、入力Unicodeコードポイントの範囲を見つけ、16進数からバイナリに変換し、上記の規則に従ってビットを挿入してから16進数に戻すことで、UTF-8に変換できます。
U+4E3E
これは0x00000800 - 0x0000FFFF
の範囲(0x4E3E < 0xFFFF
)に収まるため、表現は次の形式になります。
1110xxxx 10xxxxxx 10xxxxxx
0x4E3E
は100111000111110b
です。上記のx
にビットをドロップします(右から始めて、不足しているビットを最初に0
で埋めます):
1110x100 10111000 10111110
最初にx
スポットが残っています。0
で埋めます:
11100100 10111000 10111110
bits to hex :から変換
0xE4 0xB8 0xBE
TF-8 および TF-16 のウィキペディアの説明は適切です。
サンプル文字列の手順:
UTF-8は、Unicodeコードポイントを表すために最大4バイトを使用します。 1バイトの場合、次のパターンを使用します。
1バイトUTF-8 = 0xxxxxxx置き場 = 7ビット= 0-7Fhex
2、3、および4バイトUTF-8の初期バイトは、2、3、または4つの1ビットで始まり、その後にゼロビットが続きます。後続バイトは常に2ビットパターン10
で始まり、データ用に6ビットを残します。
2バイトUTF-8 = 110xxxxx 10xxxxxx置き場 = 5 + 6(11)ビット= 80-7FFhex
3バイトUTF-8 = 1110xxxx 10xxxxxx 10xxxxxx置き場 = 4 + 6 + 6(16)ビット= 800-FFFFhex
4バイトUTF-8 = 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx置き場 = 3 + 6 + 6 + 6(21)ビット= 10000-10FFFFhex††Unicodeコードポイントは10FFFFを超えると未定義ですhex。
コードポイントは、それぞれ1バイト、2バイト、3バイトのUTF-8シーケンスを必要とするU + 006D、U + 0416、U + 4E3Dです。バイナリに変換し、ビットを割り当てます。
U + 006D = 1101101置き場 = 1101101置き場 = 6Dhex
U + 0416 = 10000 010110置き場 = 11010000 10010110置き場 = D0 96hex
U + 4E3D = 0100 111000 111101置き場 = 11100100 10111000 10111101置き場 = E4 B8 BDhex
最終バイトシーケンス:
6D D0 96 E4 B8 BD
またはヌル終端文字列が必要な場合:
6D D0 96 E4 B8 BD 00
UTF-16は、Unicodeコードポイントを表すために2バイトまたは4バイトを使用します。アルゴリズム:
U + 0000からU + D7FFは2バイト0000を使用しますhex D7FFへhex
U + D800からU + DFFFは、4バイトUTF-16用に予約された無効なコードポイントです
U + E000〜U + FFFFは2バイトのE000を使用しますhex FFFFへhexU + 10000〜U + 10FFFFは、次のようにエンコードされた4バイトUTF-16を使用します。
- 10000を引くhex コードポイントから。
- 結果を20ビットバイナリとして表現します。
- パターン110110xxxxxxxxxx 110111xxxxxxxxxxを使用します置き場 上位10ビットと下位10ビットを2つの16ビットワードにエンコードします。
コードポイントの使用:
U + 006D = 006Dhex
U + 0416 = 0416hex
U + 4E3D = 4E3Dhex
さて、もう1つ問題があります。 16ビットWordの2バイトを最下位バイトから先に格納するマシン(いわゆるリトルエンディアンマシン)と最上位バイトを先に格納するマシン(ビッグエンディアンマシン)があります。 UTF-16は、コードポイントU + FEFF(バイトオーダーマークまたはBOMと呼ばれる)を使用して、バイトストリームにビッグエンディアンまたはリトルエンディアンのUTF-16が含まれているかどうかをマシンが判断できるようにします。
ビッグエンディアン= FE FF 00 6D 04 16 4E 3D
リトルエンディアン= FF FE 6D 00 16 04 3D 4E
ヌル終端の場合、U + 0000 = 0000hex:
ビッグエンディアン= FE FF 00 6D 04 16 4E 3D 00 00
リトルエンディアン= FF FE 6D 00 16 04 3D 4E 00 00
インストラクターが4バイトUTF-16を必要とするコードポイントを提供しなかったため、以下に例を示します。
U + 1F031 = 1F031hex - 10000hex = F031hex = 0000111100 0000110001置き場 =
1101100000111100 1101110000110001置き場 = D83C DC31hex
次のプログラムが必要な作業を行います。目的に合った「マニュアル」ではないかもしれませんが、少なくとも作業内容を確認できます。
#!/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";