ユニコード(文字コード規格)

 ユニコード(Unicode)は、文字コード規格であり、以下に出てくる「文字集合」、「コードポイント」、「UTF-16」、「サロゲート」などを規定しています。誤用をさけるために、以下「ユニコード規格」と書くことにします。また、Javaの内部コードとしては「UTF-16」が使われるので、以下では本質的でない「UTF-8」の説明はしません。

目次


コードポイント(codepoint)

 ユニコード規格では文字集合を規定しています。その集合の中に、どのような文字が含まれているかについては、Webを検索すればすぐ分かります。さて、この文字集合の中の文字を互いに区別するために、数値(0x0000から0x10FFFFまでの数値)が各文字に割り振られています。この数値をコードポイントと言います。1次元座標を考え、その各座標点(自然数だけ:原点も含む)に文字がある、というイメージを持つと良いと思います。その座標点をコードポイント(符号点)と呼ぶ訳です。1次元文字集合(1次元座標)の場合、コードポイント(座標点)はスカラー値です(2次元以上ならベクトル値)。 例えば、'あ'のコードポイントは0x3042です。1次元座標を考えているなら、 'あ'はコードポイント0x3042に在ると考えます。 ところで、 ユニコード規格のコードポイントで あることを明記するために、U+3042のようにU+をコードポイントの前に付けることがあります。

以下に、'あ'と'𠮷'のコードポイントを求めるプログラムを示します。


public class test {
    public static void main (String args []) {

    	String a;
    	int i;
    	
        a="あ";
        i=a.codePointAt(0);
        System.out.println(Integer.toHexString(i));
        
        a ="𠮷";
        i=a.codePointAt(0);
        System.out.println(Integer.toHexString(i));
    }
}

実行結果は
3042
20bb7
となります。

3042と20bb7は、それぞれ0x3042と、0x20bb7を意味します。

注意:Javaの内部コードとしては、コードポイントを使用しません。その代わり、各コードポイントを以下に記述するUTF-16方式で変換したバイナリ数値(通常、2バイトか4バイトの数値)を使用します。


UTF-16(UCS/Unicode Transformation Format)

 UTF-16は、”コードポイント”を”Javaの内部コードで使用するバイナリ数値”に変換する(エンコードする)ときに、使用する方式です。以下では、誤用をさけるため、「UTF-16方式」と書きます。

 UTF-16方式では、普通の文字(歴史的には、世界で使用されている文字をすべて2バイトで表わそうとしたことがあり、そこで収集されたよく使われている文字:コードポインで0x0000から0xFFFFに含まれる文字)は、そのままの数値で2バイトで表し、それ以外の文字を4バイトで表わします。すべての文字を4バイトで表す場合より、メモリが節約できます(メモリ使用効率が良くなる)。つまり、よく使われている文字は2バイトとするわけですから、それを4バイトとするより、よく使われている文字、1文字あたり2バイト得をします。

 それでは、4バイト文字と2バイト文字をどう区別するかが問題となります。サロゲートペアの登場です。


サロゲートペア(Surrogate Pair)

 2バイトで表すことができる数値の範囲は0x000から0xFFFFまでですから、そのうち、もとから使用されていなかったD800H〜DFFFHの範囲を、前半部分(0xD800から0xDBFF)と後半部分(0xDC00から0xDFFF)に分け、前半部分の2バイトがでてきたら、後半部分の2バイトを繋げて、4バイトにすると決めます(前半部分の2バイトと後半部分の2バイトのペアをサロゲートペアと言います)。この4バイトにコードポイントで0x10000から10FFFFまでの文字を割り当てます。どのように割り当てられているかについは、Unicode - 弘前学院聖愛中学高等学校に要領よく纏められていますので、それを参照するとよいと思います。なお、割り当てられた数値だけなら、次のプログラムで分かります。'あ'と'𠮷'に対するUTF-16方式でエンコードした数値です。'𠮷'がサロゲートペアであることが分かっていることを前提としています。前提としないならば、charAt(0);の数値を見て、サロゲートペアか否かを判断するというのも、1つの方法です。


public class test {
    public static void main (String args []) {

    	String a;
    	int i,j;
    	
        a="あ";
        i=a.charAt(0);
        System.out.println(Integer.toHexString(i));
        
         a ="𠮷";
        i=a.charAt(0);
        j=a.charAt(1);
        System.out.println(Integer.toHexString(i)+" "+ Integer.toHexString(j));
    }
}

実行結果は
3042
d842 dfb7
となります。

このように、UTF-16方式では、'あ'に対してはコードポイントと同じ2バイト数値(0x3042)にエンコードされていますが、'𠮷'に対しては、コードポイント(0x20bb7)とは異なり、サロゲートペアの4バイト数値(0xd842 0xdfb7)にエンコードされています。

繰り返しますが、javaの内部コードとして、UTF-16方式で各コードポイントに対応させたバイナリ数値(通常、2バイトか4バイトの数値)を使用します。


戻る