GB 18030: 巨大なコード・ページ

新しい中国語ユニコード標準の歴史と構造を調べる

本稿では、重要な中国語GB 18030-2000標準と、中国語市場のソフトウェアとの関係について簡単に説明します。GB 18030は、独特の問題点を抱えたまま標準として採用されました。ここでは、これらの問題点を説明すると共に、そうした問題点の対応策を提案します。

Markus Scherer (markus.scherer@us.ibm.com), Software engineer, IBM

ソフトウェア・エンジニアでありUnicodeのエキスパートであるMarkus Scherer氏は、カリフォルニア州CupertinoのIBM Unicode Technology Groupに勤務しています。現在は、オープン・ソースのUnicodeライブラリーであるUnicode国際コンポーネント (ICU) のC/C++ ライブラリーの開発リーダーを務めています。それ以前には、出身地ドイツとノース・カロライナ州で、IBMのWireless and Mobile Computingプロジェクト (GUI、変換、国際化対策など) に取り組みました。Markus氏の連絡先はmarkus.scherer@us.ibm.com です。



2001年 2月 01日

はじめに

GB 18030-2000は、拡張コード・ページとユニコードへのマッピング・テーブルを持つ、新しい中国語標準です。GB 18030が最初に発行されたのは、2000年3月17日です。世界中のソフトウェア業界からのフィードバックを受けて、コード・ページが変更され、新しいマッピング・テーブルが2000年11月30日にリリースされました。標準の本文は、2001年3月に再発行される予定です。

このコード・ページ標準がソフトウェア業界にとって重要なのは、ある日付以降に中国語市場に対してリリースするソフトウェア・アプリケーションはすべて、GB 18030をサポートしなければならないと中国が要求したためです。当初、この日付は2001年1月1日と指定されていましたが、2001年9月1日に変更されました。


主要なGBコード・ページの簡単な歴史

中国語の一般的な基本コード・ページ標準はGB 2312-1980です。6,000を超える使用頻度の高い中国漢字をエンコードしています。

ユニコードと、それに対応する標準ISO 10646 (中国ではGB 13000として採用) の重要性が高まると、GB 2312-1980の拡張版が作成されました。この拡張版のことをGBKと言い、ユニコード2.1で割り当てられる、全部で20,902の漢字がエンコードされました。GBKは正式な標準ではありませんが、幅広くインプリメントされている仕様です。

ユニコード3.0は、6,000を超える漢字を追加し、次のバージョン3.1では、さらに約42,000文字が追加される予定です。

GB 18030は、ユニコードをすべてカバーするように拡張された、ユニコード3.0向けGBKの更新版として作成されました。一般的な特徴は次のとおりです。

  • GB 18030の文字割り当ては、GB 2312-1980標準およびGBK仕様と後方互換性があります。
  • GB 18030とユニコード間のマッピング・テーブルは、GB 2312-1980とユニコード間のマッピング・テーブルには後方互換性があり、GBKとユニコード間のマッピング・テーブルの互換性については、例外がいくつかあります。GBKマッピング・テーブルと比べて異なる点の大半は、ユニコード3.0に対する更新によるものです。
  • GB 18030では、すべてのユニコード・コード・ポイントをカバーするマッピング・テーブルを指定しています。機能的には、UTF (Unicode Transformation Format) と同じですが、GBKとGB 2312-1980とのGBエンコード・テキストの互換性が確保されています。

構造

GB 18030-2000は、文字を1バイト、2バイト、または4バイトのシーケンスでエンコードしています。有効なバイト・シーケンスは次のとおりです (バイト値は16進数です)。

  • 単一バイト: 00-80 (*)
  • 2バイト: 81-fe | 40-7e、80-fe
  • 4バイト: 81-fe | 30-39 | 81-fe | 30-39

(*)注: 本稿の執筆時では、単一バイト0x80は有効として扱われていますが割り当てられておらず、単一バイト0xffは無効として扱われているようです。

GB 18030は、GBKをベースとして作成されました。GB 18030のユニコード・マッピング・テーブルは、単一バイトと2バイトのシーケンスについては、GBKのユニコード・マッピング・テーブルと同じマッピングから始めていますが、数十個の例外の文字があります。これらの文字は、ユニコード2.1では割り当てられなかったので、GBKマッピング・テーブルではユニコードPrivate-Useコード・ポイントにマッピングされました。GB 18030では、これらの文字をユニコード3.0での対応する文字に対して新たに割り当てられたコード・ポイントにマッピングしています。このため、これらの文字のGBKのバイト・シーケンスは変わっていませんが、ユニコード・マッピング・テーブルでは異なる結果を生じさせます。

さらに、この更新後のGBK部分でマップされていないユニコード・コード・ポイントはすべて、4バイト・シーケンスにマップされます。これはGB 18030の新しい特徴です。最小のユニコード・コード・ポイント (U+0080) と最小の4バイト・シーケンス (GB+81308130) を先頭として単に列挙されます。このような列挙には、40,000、すなわちGBKでカバーされなかったユニコードBMPコード・ポイントを占有する列挙と (GBの先行バイトは0x81..0x84)、100万の補足的なユニコード・コード・ポイントをカバーする列挙があります (GBの先行バイトは0x90..0xe3)。

最初のリリースのマッピング・テーブルと11月に再リリースされたマッピング・テーブルの最も大きい違いの1つは、BMPコード・ポイントへの40,000の全マッピングが変更されたことです。この主な原因は (これだけではありませんが)、BMPの列挙の先頭をU+0081ではなくU+0080にした点にあります。

Unicode Technical Report 22に記載されているXMLフォーマットの現在のユニコード・マッピング・テーブルは、ICUのWebサイトで入手できます (参考文献を参照してください)。

現在のユニコード・マッピング・テーブルには、往復マッピングしか含まれていません。オリジナルのマッピング・テーブルには、ユニコード3.0に従って更新された、GBK文字のフォールバック・マッピングが含まれていました。古いGBK Private-Useコード・ポイントは、GBコードに単方向マッピングされたのに対し、往復マッピングは (GBKと比べて) GBコードから新しい (ユニコード3.0) コード・ポイントになるように変更されました。新しいマッピング・テーブルでは、フォールバック・マッピングが削除され、Private-Useコード・ポイントが、代わりに往復マッピングによって新しい4バイト・シーケンスにマップされています。

注: 一部のGBKインプリメンテーションのように、GB 18030-2000のオリジナル・リリースでは、ユーロ通貨記号は単一バイト0x80に割り当てられていました。11月に更新されたマッピング・テーブルでは、0x80は、未割り当てとしてそのまま残され、ユーロ通貨記号は代わりに0xa2e3<->U+20acにマップされています。

GB 18030には、160万もの有効なバイト・シーケンスがありますが、ユニコードには 110万のコード・ポイントしかないので、GB 18030では、約50万のバイト・シーケンスが現在未割り当てのままとなっています。


GB 18030のインプリメンテーションに関する問題点

GB 18030には、コード・ページ・コンバーターのインプリメンテーションだけではなく、プロセス中においても問題点となる、独自の特性があります。

  • 巨大である: 前述のエンコード構造により、有効なバイト・シーケンス数は160万を超えています。コード・ページとしてはおそらく最大でしょう。
  • UTFに似ている: 110万のユニコード・コード・ポイントU+0000~U+10ffffはすべて (ただし、サロゲートのU+d800~U+dfffは除く) GB 18030コードとの間でマップされます。これには、割り当てられていないコード・ポイントと「文字以外の」コード・ポイントも含まれます。
  • GB 18030は、ユニコードとのマッピング・テーブルと同じくらい大きい、割り当て済み文字の表を使って定義されている。
  • すべてのコード・ページ・バイト・シーケンスで、1バイト目からシーケンスの長さを判別することはできない。
  • 4バイト・シーケンスは、トレール・バイト値0x30..0x39を使用しているのに対し、一般的なASCIIベースのマルチ・バイト・エンコードは、0x40以上のトレール・バイト値を使用している (0x30..0x39は、10進数に対するASCIIコード値)。つまり、単一バイト値とトレール・バイト値の間でかなり大きいオーバーラップがあるため、GB 18030テキストでのランダム・アクセスは、ほかのマルチバイト・コード・ページよりもかなり難しくなります。

こうした問題点の対応策

GB 18030のインプリメンテーションでは、マルチバイト・シーケンスの先行バイトだけでなく、少なくとも2つ目のバイトも調べて、バイト・シーケンスの長さを判別できるようにする必要があります。これは、GB 18030でハード・コーディングできます。また、このコード・ページの有効な構造全体を表す状態マシンを使って、もっと一般的な方法で実行することもできます。このような状態マシンは、純粋なデータ・ドリブンなので、あらゆるマルチバイト・エンコードに役立ちます。バイト・シーケンスが所定のコード・ページで有効かどうかをチェックする一般的なアプローチとして使用できます。

GB 18030の完全サポートについては、1つのユニコード・マッピング・テーブルですべてのコード・ポイントに対して指定されることになるので、基本的に選択肢は2つしかありません。

  • GB 18030をイン・プロセス・エンコードとして直接使用することができます。アプリケーションは、4バイト・シーケンスを含む複合マルチバイト構造を認識する必要があります。トレール・バイトについても、ほとんどすべての単一バイト値が有効です。
  • ユニコード・ベースの仕様により、ロスなくユニコードとの間で変換することができます。アプリケーションに必要なのは、この変換用のコンバーターだけで、テキストはユニコードで処理することができます。GB 18030から非ユニコード・エンコードに変換すると、テキストの一部を失うことがあります。

有効なバイト・シーケンスの数 (対象となるユニコード・コード・ポイントの数と、両者の間で定義されているマッピングの数) が多いため、標準の、純粋にマッピング・テーブル・ベースのコード・ページ・コンバーターを直接使用することはできません。マッピングは約110万あるため、簡単なマッピング・テーブルでも数メガバイトというサイズになってしまいます。初期インプリメンテーションの中には、GB 18030を完全にサポートせず、一部分しかサポートしていないものもあります。

大量の定義済みマッピングを簡単に効率よく処理する方法は、4バイト・シーケンスの大半をアルゴリズムに従って処理する方法です。これが可能なのは、GB 18030の4バイト・シーケンスとユニコード・コード・ポイント間のマッピングは、列挙プロセスの結果だからです (前述の「構造」の説明を参照してください)。マッピング・テーブルの大部分に、ユニコード・コード・ポイントとバイト・シーケンスの両方で1つずつ正確に位置がずれている項目が含まれています。このように連続列挙された範囲を自動的にいくつか抜き出すことができます (この抜き出しの詳細については、このページ を参照してください)。その結果、実際のマッピング・テーブルに保管する必要があるのは、残りのマッピングだけとなり、範囲は、コンバーター内の特殊なコードによってマッピングされます。

前述のXMLマッピング・ファイルには、約31000ものマッピングをカバーするこのような範囲が13含まれています。この数は、ユニコードとEast Asianコード・ページ間のマッピング・テーブルでは珍しいことではありません。このようなマッピング・テーブルを使用しているコンバーターは、まず明示的なマッピングを使用します。結果が「未割り当て」の場合は、入力が入っている範囲を探し、このような範囲が存在する場合はアルゴリズムに従ってマップし、存在しない場合は入力を未割り当てとして処理します (もちろん、不当なシーケンスは、通常どおり、アプリケーションに従って処理しなければなりません)。

補助的なユニコード・コード・ポイントの1つの範囲をアルゴリズムに従って処理すると、実際のマッピング・テーブルからBMP以外のすべてのユニコード・コード・ポイント・マッピングが必要なくなります。

原則的に、4バイト・シーケンスに関係するマッピングはすべて、連続した範囲として抜き出すことで、アルゴリズムに従って処理することができます。これらの範囲の中には、1つのマッピングしか含まれていないものもあります。このため、4バイト・シーケンスの変換には時間がかかりますが、残りのマッピング・テーブルには、単一バイトと2バイトのGB 18030とユニコード BMPコード・ページ間のマッピングしか入らないようにすることができます。残りのマッピング・テーブルには、約24,000の項目しか含まれません。


GB 18030とユニコード間のマッピング連続列挙マッピングのアルゴリズム

次に、マッピング仕様の連続列挙範囲内でのGB 18030とユニコード間のマッピングのアルゴリズム例を示します。コードは疑似コードです。このアルゴリズムを一般的な方法でインプリメントすると、マッピング・テーブルだけでなく範囲情報を格納することができます。ただし、必要なければ、現在このアルゴリズムが本当に役立つコード・ページはGB 18030だけです。

次の例で、XMLファイル内の列挙マッピングの範囲について考えましょう (この範囲で、補足的なユニコード・コード・ポイントをすべてカバーします)。

   <range uFirst="10000" uLast="10FFFF"
           bFirst="90 30 81 30" bLast="E3 32 9A 35"
           bMin="81 30 81 30" bMax="FE 39 FE 39"/>

XMLファイル内のバイト値およびコード・ポイント値はすべて16進数であることに注意してください。

GB 18030の4バイト・シーケンスをアルゴリズムに従って処理するためには、線形化する、つまり4バイト・シーケンスごとに1つの数を生成して、2つの値の差がバイト・シーケンス間の字句上の差と同一となるようにする必要があります。

   int linear(byte bytes[4]) {
        return ((bytes[0]*10+bytes[1])*126+bytes[2])*10+bytes[3];
    }

係数10と126は、bMinとbMaxに従ったバイト位置におけるバイト値の数です。10は0x30..0x39に相当し、126は0x81..0xfeに相当します。この関数の結果は、4バイト・シーケンスのオーダーと、それに続く序数です。

バイト・シーケンスの線形値を指定すると、バイト・シーケンスそのものを計算することができます。

    byte[4] unLinear(int lin) {
        byte result[4];
        lin-=linear(0x81, 0x30, 0x81, 0x30); // zero-base the linear value
        result[3]=0x30+lin%10;  lin/=10;
        result[2]=0x81+lin%126; lin/=126;
        result[1]=0x30+lin%10;  lin/=10;
        result[0]=0x81+lin;
        return result;
    }

連続列挙範囲ごとに、次の文が真でなければなりません。uLast-uFirst == linear(bLast)-linear(bFirst)

GB 18030の4バイト・シーケンスからユニコード・コード・ポイントへのマッピング:

    int mapToUnicode(byte bytes[4]) {
        int lin=linear(bytes);
        for each range {
            if(linear(bFirst)<=lin<=linear(bLast)) {
                // range found
                return uFirst+(lin-linear(bFirst));
            }
        }
        // the byte sequence is not in any known range
        return error;
    }

ユニコード・コード・ポイントからGB 18030の4バイト・シーケンスへのマッピング:

    byte[4] mapFromUnicode(int u) {
        for each range {
            if(uFirst<=u<=uLast) {
                // range found
                return unLinear(linear(bFirst)+(u-uFirst));
            }
        }
        // code point u is not in any known range
        return error;
    }

ここで説明したテクニックとアルゴリズムのインプリメンテーション例については、ICU's ucnvmbcs.c を参照してください (license を参照してください)。


結論と展望

本稿では、中国語市場をターゲットとする今後のアプリケーションにインプリメントしなければならない、新しい中国語コード・ページ標準GB 18030-2000の歴史と構造について説明しました。独特の機能と問題点について説明し、ソリューション案を紹介しました。

中国語標準当局がマッピング・テーブルをリリースし、ソフトウェア業界がこのマッピング・テーブルを採用すれば、これは、コード・ページ標準のインプリメンテーションを業界全体で統一できる、またとないチャンスです。

この標準は、オリジナル以降、変更が重ねられています。新しいマッピング・テーブルは2000年11月にリリースされました。標準の本文は2001年3月に再発行される予定です。適用日は2001年9月1日に延期され、この日付以降に新たにリリースされたソフトウェアはGB 18030をサポートしなければなりません。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=232917
ArticleTitle=GB 18030: 巨大なコード・ページ
publish-date=02012001