18.4.1.3 Unicode

このページでは,全世界の文字を1つの文字集合に収めてしまおうという考えで作られた Unicode について説明をします.

Unicode の概要

文字集合 Unicode 中の文字は U+FF60, U+2000B などと, U+ の後ろに 16 進数 4 桁以上を使って表記することになっています. 先頭の 256 文字(U+0000 から U+00FF まで)は ISO-8859-1 と同じになっています.
Unicode は,初期では 16 ビット(2 バイト)で全ての文字を扱おうという計画で開発が進められていました.しかし 16 ビットでは足りず.結局 16 ビットの「面」17 個からなる 21 ビットの文字集合となりました.
執筆時点(2012 年 3 月)では,実際に「図形としての」文字が割り当てられているのは 3 つの面だけとなっています.

  • 第 0 面(U+0000 から U+FFFF)は基本多言語面 (BMP, Basic Multilingual Plane) といいます. 私たちが日常使う言語の大部分はこの面に収まっています.JIS 基本漢字,JIS 仮名,JIS 補助漢字もこの面の中に収まっています.
  • 第 1 面(U+10000 から U+1FFFF)は追加多言語面 (Supplementary Multilingual Plane) といいます.楔形文字等の古代文字,絵文字,数式用アルファベットなどが含まれています.
  • 第 2 面(U+20000 から U+2FFFF)は追加漢字面 (Supplementary Ideographic Plane) といい,BMP に収まらなかった漢字が追加で収録されています.JIS X 0213 の文字も,300 字程度がここに収められています.

他にも,第 14 面(U+E0000 から U+EFFFF)・第 15 面(U+F0000 から U+FFFFF)・第 16 面(U+100000 から U+10FFFF)中にも意味を割り当てられている「文字」があります.
元々 16 ビットで賄おうという背景があったため,Unicode では日本・中国・韓国で用いられている漢字を統合しており(CJK 統合漢字,CJK Unified Ideographs),このことが批判の対象になったりもしているようです.漢字統合でよくいわれる話題として.同じ番号に対応した漢字が,日本語フォント・中国語フォントなどによって違ったことになるということがあります.
CJK における字形の違い
Unicode の符号化方式としては,次の UTF-8 と UTF-16 が有名です.

UTF-8
1 バイト単位の符号化方法です.各文字を表現するのに使うバイト数は文字によって異なり,番号が大きいほどバイト数が多くなっていくのが特徴です. 例えば,

  • ASCII 文字は 1 バイト.
  • ISO-8859-1 の残り,ギリシャ文字・キリル文字などは 2 バイト.
  • 多くの和文文字(半角カナも含む)は 3バイト.
  • U+10000 以上の文字(漢字の一部を含む)は 4 バイト.

となっています.ASCII 文字以外は,最上位ビットが 1 のバイト列で符号化されます.

UTF-16
一方,UTF-16 は,各文字を 2 バイトの整数倍で表すというものです.BMP はそのまま 16 ビットで収められ,第1面以降はサロゲートペアと呼ばれる仕組みを用いて 4 バイトで表します.

近年,Unicode の,特に UTF-8 の利用が急速に広がっています.Windows, Mac OS X, Java などでは内部で Unicode を使用していますし,Linux などではシステムの文字コードを UTF-8 にしてしまうこともあります.

Unicode と JIS 漢字との対応

Unicode と従来のシフト JIS 系統の文字コードとの変換においては面倒な事態が発生しています.ここでは有名な 2 つを取り上げます.

波ダッシュ問題

波ダッシュは,JIS 漢字で(1 面)1 区 33 点にある文字「〜」で,JIS 規格による Unicode との対応では U+301C の文字に対応しています.
しかし,Unicode の初期の例示字形ではこの文字は「下がって上がる」という JIS 漢字とは異なる例示字形が採用され,その影響で CP932 では波ダッシュを U+FF5E (全角チルダ,「~」)に割り当ててしまいました.この非互換性が,いわゆる波ダッシュ問題です.
現在執筆に用いている Windows Vista では「から」を漢字変換すると全角チルダの方が出力され,波ダッシュは少々荒い文字で表示されてしまいます.最近のフォントでは両方「上がって下がる」形になりましたが,古いフォントだと波ダッシュの字形が上下逆になってしまっていることもあるようです.
なお,JIS 拡張漢字では,波ダッシュと別の文字として(全角)チルダがおさめられています.

YEN SIGN 問題

hwb18.4.1.1 ASCII と JIS 仮名 で触れましたが,ASCII と JIS ローマ字の間には,5C(16) に対応する文字が \(バックスラッシュ)と ¥(半角円記号)になっているという差異がありました.JIS ローマ字を採用している シフト JIS や,その亜種の CP932 でも同じです.このため,特に Windows で用いられるフォントなどでは,5C(16) に対応する文字が半角円記号になっていることが多いです.
一方,欧米圏で伝統的に使われていた ISO-8859-1 では,バックスラッシュとは別に A5(16) の位置に(半角)円記号を割り当てています.さて,Unicode は,ISO-8859-1 をベースとして開発されたので,前に述べたように最初の 256 文字は ISO-8859-1 と同じです.そのため,バックスラッシュと半角円記号は別々の文字コードを持っていることになります.
よって,シフト_JIS の半角円記号(5C(16))と,Unicode のバックスラッシュ \ (U+005C),Unicode の半角円記号 ¥ (U+00A5) との変換に関して問題が起こるわけです.これが YEN SIGN 問題です.

Mac 環境での \ (U+005C) と ¥ (U+00A5) の打ち分け

Mac OS X の標準では,¥ と書かれている del の左のキーを押すと,Unicode の半角円記号 ¥ (U+00A5) が出力されます.また,右shiftの左の\ と書かれているキーを押しても,\ (U+005C) は入力されず,代わりに _ が入力されるだけです.
一般的に,Unicode のバックスラッシュ \ (U+005C) を打つには, ¥ とします.但し,いくつかの例外があります.

  • mi(hwb8.2 mi を参照)では,miモード設定編集¥ キーを押したときバックスラッシュを入力する のチェックボックスをオンにすることで,\ (U+005C) を入力することができます.この状態のとき,¥ (U+00A5) の入力には 編集¥ を入力 を使います.
  • Emacs(hwb8.4 Emacs 参照)では,¥ キーで \ (U+005C) を入力できるようです.
  • ターミナル(hwb15.2 ターミナルの基本的な使い方 参照)でも,¥ キーで \ (U+005C) を入力できるようです.

「ことえり」の環境設定入力文字JIS キーボードの ¥ キーで入力する文字¥ から \ (U+005C) を入力するようにもできます.

YEN SIGN 問題の実例

簡単に YEN SIGN 問題の実例を紹介します.ここの部分は環境によって文字が化ける可能性があります.
次のファイル test.c を用意します.これは C 言語というプログラミング言語で書かれたプログラムのソースファイルです.

#include<stdio.h> int main(void) { printf("test\ntest\n"); return 0; }

このファイルを gcc というコマンドでコンパイルし,実行させると,test という文字列が 2 行出力されます.
gcc test.c && ./a.outreturn2
test test

これは,ソース中の「\n」が,改行を表す特殊文字であるからです.ここの「\」は 5C(16) 番の文字であることに注意してください.
test.c は ASCII だけで書かれていますが,これをシフト JIS で書かれていると思って,Unicode の符号化の一つである UTF-8 に変換します.変換結果を,test-sjis.c とします.そして,test-sjis.c をコンパイルし,実行させてみます.
iconv -f Shift_JIS -t UTF-8 test.c  > test-sjis.creturn2
gcc test-sjis.c && ./a.outreturn2
test¥ntest¥n

すると,出力される文字列が「test¥ntest¥n」と 1 行になり,またこの文字列の直後にシェルプロンプトが表示されました.元々のソース中の 5C(16) が,シフト JIS では半角円記号であるため,それを Unicode に変換すると ¥ (U+00A5) となってしまう(それを UTF-8 で符号化すると C2A5(16) というバイト列になる)ことによります.
しかし,Windows では,5C(16) 番の文字をディレクトリの区切りとして用いています(参考:hwb14.4.1 ディレクトリ).この関係上,CP932 と Unicode の間の変換表は,シフト JIS と Unicode の間の変換表とは違ったものとなっています.
test.c を CP932 で書かれていると思って,UTF-8 に変換してみると,5C(16) は \ (U+005C) へと変換され,バイト列としても test.c と test-cp932.c は同じものになります.よって,きちんと test の出力が 2 行になります.
iconv -f CP932 -t UTF-8 test.c > test-cp932.creturn2
gcc test-cp932.c && ./a.outreturn2
test test