昨日の続き。
ていうか、さっそく自分で間違いを見つけてしまった。
昨日こう書いた。
(16面で最大の文字はU+10FFFFである。)
U+0000からU+10FFFFまで使えるんだったら1,114,112文字入るんじゃないですかと思われるかもしれないが、うちの2,048コードポイントはサロゲート領域なので、文字数としては1,114,112-2,048で1,112,064文字である。
スミマセンでした。
ていうか、さっそく自分で間違いを見つけてしまった。
昨日こう書いた。
216(もともとのBMP)上の文だと、Unicodeで使える最大のコードポイントはU+10F800であるように読めるが、最大のコードポイントはU+10FFFFである。
+1,0242(サロゲートペアで増えた分)
-2,048(サロゲートで使う分)
だから、1,112,064コードポイントが使用可能である。
1,112,064は16進数で10F800であるから、UCS-4で言うと1群16面までしか入らない。
(16面で最大の文字はU+10FFFFである。)
U+0000からU+10FFFFまで使えるんだったら1,114,112文字入るんじゃないですかと思われるかもしれないが、うちの2,048コードポイントはサロゲート領域なので、文字数としては1,114,112-2,048で1,112,064文字である。
スミマセンでした。
まとめると、
・コードポイントとしてはU+0000~U+10FFFFまで1,114,112個(16面)
・うち以下の2,048個がサロゲート用なので文字としては欠番
前半:0xD800-0xDBFF(1,024コードポイント)
後半:0xDC00-0xDFFF(1,024コードポイント)
・よって使える文字数としては1,114,112-2,048で1,112,064文字
である。
ただし、前にも書いた通り下の1オクテット(Unicodeでは8ビットをこう言う)がFE、FFの字は非文字なので、最大のUnicodeコードポイントはU+10FFFDという言い方もある。
★
では、実際にU+10000からU+10FFFFまでのBMP外の文字を、どのようにしてUTF-16文字2文字(サロゲートペア)に写すかを研究する。
なお、UTF-16にはビッグエンディアンとリトルエンディアンがある。
ビッグエンディアンはBMPの範囲にあるたとえばU+6F22という字だったら(「漢」という字)そのまま0x6F22という字になる。
リトルエンディアンは0x226Fとオクテット単位で反転する。
これは「ガリヴァー旅行記」に出てくるゆで卵を小さい方から食べるか大きい方から食べるかで戦争になる架空の民族派閥から名前を取ってbig endian、little endianと言っているものだ。
先日Webを見ていたら堂々と「ビッグ・インディアン」「リトル・インディアン」と書いていたが、それは童謡「10人のインディアン」と混ざっている。
間違いだ。
ここではとりあえずUTF-16はビッグエンディアンのこと、という前提で話を進める。
サロゲートペアの前半は0xD800-0xDBFFである。
2進数で言えば1101 1000 0000 0000b~1101 1011 1111 1111bだ。
先頭の6ビットは1101 10固定で、残り10ビットが00 0000 0000~11 1111 1111で変化する。
サロゲートペアの後半は0xDC00-0xDFFFである。
2進数で言えば1101 1100 0000 0000b~1101 1111 1111 1111bである。
先頭の6ビットは1101 11固定で、残り10ビットが00 0000 0000~11 1111 1111で変化する。
つまり、10ビットのコード2つが使える。
この20ビットの領域に、U+10000からU+10FFFFまでのコードを押し込めば良い。
ところが、最大のU+10FFFFは、2進数で1 0000 1111 1111 1111 1111である。
21ビットだ!
入らない。
U+100000(1 0000 0000 0000 0000 0000b)から、0xFFFF個+1個(65536個)、第16面ぶんが入らないのである。
ちなみに15面と16面はPUA(Private Use Area、私用領域)に予約されている。
「あ、ぼくちょっと今日は私用で早く帰ります」というメッセージを書くために使うわけではなく(どういうこと?)、組織内で通じる外字を割り当てるために使うことになっている。
実際には、U+FFFFまで(1面、BMP)はサロゲートペアを使わずにもうコード化されてしまっているので、その分は使わなくてよい。
よって、U+10FFFFからU+10000を引く。(1面ぶんズラす)
0xFFFFF=1111 1111 1111 1111 1111bになって、見事20ビットに収まる。
これを10ビットずつ分けて、11 1111 1111と11 1111 1111にして、サロゲートエリアの各10ビットに押し込む。1個目は、1101 1011 1111 1111b(DBFF)で、2個目は1101 1111 1111 1111b(DFFF)だ。
よって、U+10FFFFはビッグエンディアンでは0xDBFF DFFFになる。
(まあ、サロゲートエリアで最大のコードは0xDBFF DFFFだから当然だ。)
では最小のBMP外文字、SMPのU+10000(古代ギリシャで使われたという線文字Bのこの字)を計算する。
まず1面ぶんズラすためにU+10000を引くとゼロになる。
これを10ビットずつに分けて、0000 0000 00と00 0000 0000をサロゲートエリアの各10ビットに押し込む。
1個目は、1101 1000 0000 0000b(D800)で、2個目は1101 1100 0000 0000b(DC00)だ。
よって、U+10000はビッグエンディアンでは0xD800 DC00 になる。
(これもサロゲートエリアで最小のコードは0xD800 DC00だから当然だ。)
辰吉𠀋一郎の𠀋はU+2000Bで、SIPである。
この字をサロゲートペアに入れてみよう。
まずU+10000を引いて1面分ズラす。
0x1000Bになる。
これを2進数にすると0001 0000 0000 0000 1011になる。
(20ビットにするために上から3つゼロを補った。)
これを10ビットずつ分けると 00 0100 0000 と 00 0000 1011 になる。
サロゲートエリアの各10ビットに押し込む。
1個目は、1101 1000 0100 0000bなので、D840。
2個目は、1101 1100 0000 1011bなので、DC0Bになる。
よって、U+10000はビッグエンディアンでは0xD840 DC0B になる。
下の画面はUnihan Databaseで𠀋を引いてみたところだ。
ちゃんとUTF-16がD840 DC0Bになっている。
合ってるー。
では、実際にサロゲートペアに対応したアプリケーションで、𠀋の字を入力してみよう。
まず、Windows付属のメモ帳に𠀋をコピペして「名前を付けて保存」を選び「文字コード」を選択する。
これがいつも悩みどころである。
「ANSI」というのがある。
これはAmerican National Standards Institute(米国国家規格協会)の略で、アメリカの規格機関のことである。
まあASCII(American Standard Characters for Information Interchange。出版社の名前ではない)のことをANSIと言う(Windows 1252の右面のことをHigh ANSIと言う)人もいるから、ASCIIで保存されるのなら分からないでもない。
しかし、ここで「ANSI」を選ぶと保存される文字コードは、Microsoftが拡張したシフトJISであるところのCP932である。
まあ、アメリカ版のNotepad.exeのUIをそのまま持ってきたということだろうが納得が行かない。
次に「Unicode」と言うのがある。
ここを選ぶと、先に答えを言ってしまうが、UTF-16(リトルエンディアン、BOM付き)になる。
WindowsでUTF-16というとリトルエンディアンのことだ。
次に「Unicode(Big Endian)」と言うのがある。
ここを選ぶと、UTF-16(ビッグエンディアン、BOM付き)になる。
で、最後に「UTF-8」と言うのがある。
ここを選ぶと、UTF-8になる。
ところが、UTF-8もUTF-16と並んで、Unicodeの一部なのである。
昔は「深沢さん、Unicodeにしてくれって言っておいたのに、UTF-8になってましたよ」と言われたことがある。
その時は、ぼくもプロのビジネスマンなので、「ハイ、すみませんでした」と言って素直にUTF-16(リトルエンディアン、BOMつき)にしたのである。
この「UTF-16、リトルエンディアン、BOMつき」を「Unicode」、「UTF-16、ビッグエンディアン、BOMつき」を「Unicode(Big Endian)」、そして「CP932」を「ANSI」と言うのは、完全なMicrosoft方言なので、注意したい。
話が長くなったが、ここでは「Unicode(Big Endian)」を選んで保存する。
上から、保存したファイルのアイコン、それを「メモ帳」で開いたもの、それをフリーウェアの16進ダンプ用ソフトウェア「xdump」(リンクはベクター)で開いたものである。
ダンプは何を使っても良いが、xdumpはフリーで、余計なDLLを必要としないので気に入っている。
最初にFE FFと書いている。
これはU+FEFFというUnicode文字であって、ZWNBS(Zero Width Non Breaking Space ゼロ幅の改行なし空白)という立派な文字であるが、特にUnicodeファイルの先頭に書いてエンコーディングとエンディアンを示すことが出来る。
この用途で書くZWNBSのことをBOM(Byte Order Mark)と言う。
ビッグエンディアンのBOMはFEFFである。
逆にソフトウェアは、ファイルの先頭にFEFFを発見すると、UTF-16でビッグエンディアンだなー、と知ることが出来る。
ではオクテットごとに逆になったFFFEがあると、U+FFFEは非文字で文字の割り当てが許されていないので、UTF-16でリトルエンディアンなんだなー(先頭にはオクテットごとに逆順になったZWNBSがあるなー)と知ることが出来る。
で、xdumpの続きを見ると、見事にD8 40 DC 0Bになっている。
さっき計算したサロゲートペアと一緒である。
合ってるー。
ではせっかくなので同じメモ帳で「Unicode」を選択して保存し直してみる。
先頭はFFFEになっているが、これはさっき説明したリトルエンディアンのU+FEFF(ZWNBS、BOM)である。
で、それに続くバイト列は40 D8 0B DCになっている。
このようにUTF-16のリトルエンディアンは、サロゲートペアになってもオクテット範囲で反転する。
ビッグエンディアンで0xABCD EFGHというサロゲートペアがあったとすると、リトルエンディアンでは0xCDAB GHEFになる。
最小のSIP文字U+10000は、ビッグエンディアンで0xD800 DC00であったので、リトルエンディアンでは0x00D8 00DCになる。
最大のUnicodeU+10FFFFは、0xDBFF DFFFであったので、リトルエンディアンでは0xFFDB FFDFになる。
分かってしまえばカンタンである。
・コードポイントとしてはU+0000~U+10FFFFまで1,114,112個(16面)
・うち以下の2,048個がサロゲート用なので文字としては欠番
前半:0xD800-0xDBFF(1,024コードポイント)
後半:0xDC00-0xDFFF(1,024コードポイント)
・よって使える文字数としては1,114,112-2,048で1,112,064文字
である。
ただし、前にも書いた通り下の1オクテット(Unicodeでは8ビットをこう言う)がFE、FFの字は非文字なので、最大のUnicodeコードポイントはU+10FFFDという言い方もある。
★
では、実際にU+10000からU+10FFFFまでのBMP外の文字を、どのようにしてUTF-16文字2文字(サロゲートペア)に写すかを研究する。
なお、UTF-16にはビッグエンディアンとリトルエンディアンがある。
ビッグエンディアンはBMPの範囲にあるたとえばU+6F22という字だったら(「漢」という字)そのまま0x6F22という字になる。
リトルエンディアンは0x226Fとオクテット単位で反転する。
これは「ガリヴァー旅行記」に出てくるゆで卵を小さい方から食べるか大きい方から食べるかで戦争になる架空の民族派閥から名前を取ってbig endian、little endianと言っているものだ。
先日Webを見ていたら堂々と「ビッグ・インディアン」「リトル・インディアン」と書いていたが、それは童謡「10人のインディアン」と混ざっている。
間違いだ。
ここではとりあえずUTF-16はビッグエンディアンのこと、という前提で話を進める。
サロゲートペアの前半は0xD800-0xDBFFである。
2進数で言えば1101 1000 0000 0000b~1101 1011 1111 1111bだ。
先頭の6ビットは1101 10固定で、残り10ビットが00 0000 0000~11 1111 1111で変化する。
サロゲートペアの後半は0xDC00-0xDFFFである。
2進数で言えば1101 1100 0000 0000b~1101 1111 1111 1111bである。
先頭の6ビットは1101 11固定で、残り10ビットが00 0000 0000~11 1111 1111で変化する。
つまり、10ビットのコード2つが使える。
この20ビットの領域に、U+10000からU+10FFFFまでのコードを押し込めば良い。
ところが、最大のU+10FFFFは、2進数で1 0000 1111 1111 1111 1111である。
21ビットだ!
入らない。
U+100000(1 0000 0000 0000 0000 0000b)から、0xFFFF個+1個(65536個)、第16面ぶんが入らないのである。
ちなみに15面と16面はPUA(Private Use Area、私用領域)に予約されている。
「あ、ぼくちょっと今日は私用で早く帰ります」というメッセージを書くために使うわけではなく(どういうこと?)、組織内で通じる外字を割り当てるために使うことになっている。
実際には、U+FFFFまで(1面、BMP)はサロゲートペアを使わずにもうコード化されてしまっているので、その分は使わなくてよい。
よって、U+10FFFFからU+10000を引く。(1面ぶんズラす)
0xFFFFF=1111 1111 1111 1111 1111bになって、見事20ビットに収まる。
これを10ビットずつ分けて、11 1111 1111と11 1111 1111にして、サロゲートエリアの各10ビットに押し込む。1個目は、1101 1011 1111 1111b(DBFF)で、2個目は1101 1111 1111 1111b(DFFF)だ。
よって、U+10FFFFはビッグエンディアンでは0xDBFF DFFFになる。
(まあ、サロゲートエリアで最大のコードは0xDBFF DFFFだから当然だ。)
では最小のBMP外文字、SMPのU+10000(古代ギリシャで使われたという線文字Bのこの字)を計算する。
まず1面ぶんズラすためにU+10000を引くとゼロになる。
これを10ビットずつに分けて、0000 0000 00と00 0000 0000をサロゲートエリアの各10ビットに押し込む。
1個目は、1101 1000 0000 0000b(D800)で、2個目は1101 1100 0000 0000b(DC00)だ。
よって、U+10000はビッグエンディアンでは0xD800 DC00 になる。
(これもサロゲートエリアで最小のコードは0xD800 DC00だから当然だ。)
辰吉𠀋一郎の𠀋はU+2000Bで、SIPである。
この字をサロゲートペアに入れてみよう。
まずU+10000を引いて1面分ズラす。
0x1000Bになる。
これを2進数にすると0001 0000 0000 0000 1011になる。
(20ビットにするために上から3つゼロを補った。)
これを10ビットずつ分けると 00 0100 0000 と 00 0000 1011 になる。
サロゲートエリアの各10ビットに押し込む。
1個目は、1101 1000 0100 0000bなので、D840。
2個目は、1101 1100 0000 1011bなので、DC0Bになる。
よって、U+10000はビッグエンディアンでは0xD840 DC0B になる。
下の画面はUnihan Databaseで𠀋を引いてみたところだ。
ちゃんとUTF-16がD840 DC0Bになっている。
合ってるー。
では、実際にサロゲートペアに対応したアプリケーションで、𠀋の字を入力してみよう。
まず、Windows付属のメモ帳に𠀋をコピペして「名前を付けて保存」を選び「文字コード」を選択する。
これがいつも悩みどころである。
「ANSI」というのがある。
これはAmerican National Standards Institute(米国国家規格協会)の略で、アメリカの規格機関のことである。
まあASCII(American Standard Characters for Information Interchange。出版社の名前ではない)のことをANSIと言う(Windows 1252の右面のことをHigh ANSIと言う)人もいるから、ASCIIで保存されるのなら分からないでもない。
しかし、ここで「ANSI」を選ぶと保存される文字コードは、Microsoftが拡張したシフトJISであるところのCP932である。
まあ、アメリカ版のNotepad.exeのUIをそのまま持ってきたということだろうが納得が行かない。
次に「Unicode」と言うのがある。
ここを選ぶと、先に答えを言ってしまうが、UTF-16(リトルエンディアン、BOM付き)になる。
WindowsでUTF-16というとリトルエンディアンのことだ。
次に「Unicode(Big Endian)」と言うのがある。
ここを選ぶと、UTF-16(ビッグエンディアン、BOM付き)になる。
で、最後に「UTF-8」と言うのがある。
ここを選ぶと、UTF-8になる。
ところが、UTF-8もUTF-16と並んで、Unicodeの一部なのである。
昔は「深沢さん、Unicodeにしてくれって言っておいたのに、UTF-8になってましたよ」と言われたことがある。
その時は、ぼくもプロのビジネスマンなので、「ハイ、すみませんでした」と言って素直にUTF-16(リトルエンディアン、BOMつき)にしたのである。
この「UTF-16、リトルエンディアン、BOMつき」を「Unicode」、「UTF-16、ビッグエンディアン、BOMつき」を「Unicode(Big Endian)」、そして「CP932」を「ANSI」と言うのは、完全なMicrosoft方言なので、注意したい。
話が長くなったが、ここでは「Unicode(Big Endian)」を選んで保存する。
上から、保存したファイルのアイコン、それを「メモ帳」で開いたもの、それをフリーウェアの16進ダンプ用ソフトウェア「xdump」(リンクはベクター)で開いたものである。
ダンプは何を使っても良いが、xdumpはフリーで、余計なDLLを必要としないので気に入っている。
最初にFE FFと書いている。
これはU+FEFFというUnicode文字であって、ZWNBS(Zero Width Non Breaking Space ゼロ幅の改行なし空白)という立派な文字であるが、特にUnicodeファイルの先頭に書いてエンコーディングとエンディアンを示すことが出来る。
この用途で書くZWNBSのことをBOM(Byte Order Mark)と言う。
ビッグエンディアンのBOMはFEFFである。
逆にソフトウェアは、ファイルの先頭にFEFFを発見すると、UTF-16でビッグエンディアンだなー、と知ることが出来る。
ではオクテットごとに逆になったFFFEがあると、U+FFFEは非文字で文字の割り当てが許されていないので、UTF-16でリトルエンディアンなんだなー(先頭にはオクテットごとに逆順になったZWNBSがあるなー)と知ることが出来る。
で、xdumpの続きを見ると、見事にD8 40 DC 0Bになっている。
さっき計算したサロゲートペアと一緒である。
合ってるー。
ではせっかくなので同じメモ帳で「Unicode」を選択して保存し直してみる。
先頭はFFFEになっているが、これはさっき説明したリトルエンディアンのU+FEFF(ZWNBS、BOM)である。
で、それに続くバイト列は40 D8 0B DCになっている。
このようにUTF-16のリトルエンディアンは、サロゲートペアになってもオクテット範囲で反転する。
ビッグエンディアンで0xABCD EFGHというサロゲートペアがあったとすると、リトルエンディアンでは0xCDAB GHEFになる。
最小のSIP文字U+10000は、ビッグエンディアンで0xD800 DC00であったので、リトルエンディアンでは0x00D8 00DCになる。
最大のUnicodeU+10FFFFは、0xDBFF DFFFであったので、リトルエンディアンでは0xFFDB FFDFになる。
分かってしまえばカンタンである。