次のページ 前のページ 目次へ

6. あなたのプログラムで Unicode を扱えるようにする

6.1 C/C++

C 言語の `char' 型は 8 ビットですが、 これは扱える最小のサイズだからです。

通常のテキストハンドリング

1995 年に ISO/ANSI C standard に追加された修正条項に記述されているのは、 "wide character/ワイド文字" 型である `wchar_t'と、 <string.h> および <ctype.h> (それぞれ <wchar.h> および <wctype.h> で宣言されてい ます)にある一連の関数と、`char *' と `wchar_t *' 間の 一連の 変換関数 (<stdlib.h> で宣言されています)です。

これらの API の良いリファレンス

これらの API を使う利点

これらの API の欠点

可搬性(Portability)について

`wchar_t' が Unicode で、マルチバイトの文字列 `char *' が UTF-8 でエンコードされているかどうかはプラットフォームや、時にはロカー ルにも依存しています。

Single Unix specification では `wchar_t' 型についてこのように述べられています:

プロセスの全てのワイド文字コードは、固定長のビットで構成されている。これ に対して文字(character)を構成するバイト数は可変である。文字を表現するバ イト(あるいはバイトの並び)は、ワイド文字コードとして表現することもできる。 つまりワイド文字コードにより、固定長でテキストデータを扱うことができる。 全ビットがゼロのワイド文字コードはヌルのワイド文字コードで、ワイド文字の 文字列の終りを表す。可搬性のある文字セット (著者注:つまり ASCII) を表現 するために使用されるワイド文字の値は、1 文字で文字を表している時にはその (ASCII での)値に等しくなる。その他の文字のワイド文字コードはロケールおよ び実装に依存する。状態シフトバイトにはワイド文字コード表現はない。

結論としては、可搬性のあるプログラムでは非 ASCII 文字を文字列のリテラル として使うべきではないということです。つまり Unicode の二重引用符がコー ド U+201C および U+201D ということを知っていたとしても、C のプログラムでは 文字列のリテラル L"\u201cHello\u201d, he said""\xe2\x80\x9cHello\xe2\x80\x9d, he said" を使用すべきではありません。そのかわりに GNU gettext を使用し て gettext("'Hello', he said") と書き、メッセージデータベース en.UTF-8.po を作成して "'Hello', he said" を "\u201cHello\u201d, he said" に翻訳します。

以下は各 UNIX における ISO/ANSI C 機能の可搬性を調査したものです。GNU glibc-2.2 はこれら全てをサポートする予定ですが、現在の所は(まだ出ていな いため)以下のもので我慢するしかありません。

GNU glibc-2.0.x, glibc-2.1.x

Solaris 2.7

OSF/1 4.0d

Irix 6.5

HP-UX 11.00

AIX 4.2

以上より、再開可能(restartable)かつマルチスレッドセーフな wcsr/mbsr 関数 を使うことをお勧めします。関数が無いシステム(Irix, HP-UX, AIX)のことは忘れ てしまって、UTF-8 ロケール のプラグイン libutf8_plug.so(下記参照のこと)を、 wcsr/mbsr 関数を使用したプログラムをコンパイルできるシステム(Linux, Solaris, OSF/1)で使用しましょう。

Sun の同様なアドバイス http://www.sun.com/software/white-papers/wp-unicode/ の "Internationalized Applications with Unicode" セクションにはこのように書 かれています:

正しくアプリケーションを国際化するには、次のガイドラインに沿う必要がある:

  1. Unicode への直接のアクセスは避ける。 これはプラットフォーム上の国際化フレームワークの仕事です
  2. POSIX モデルの、マルチバイトおよび ワイド文字インターフェースを使用する
  3. 国際化フレームワークの提供する言語および文化依存操作の API のみを呼びだす
  4. コードセット非依存のままにする

もし何かの理由で、`wchar_t' が Unicode だとどうしても仮定しなければなら ない(例えば一部の Unicode 文字に特別な処理を行ないたい時)ようなコードが 必要な時には、コードのその部分を is_locale_utf8() の結果を見て 動作するようにするべきです。そうしない場合そのプログラムは、ロケールや他 のプラットフォームでの動作の記述でぐちゃぐちゃになってしまうでしょう。 is_locale_utf8 関数は utf8locale.h で宣言され、 utf8locale.c で定義されています。

libutf8 ライブラリ

ISO/ANSI C API の可搬性のある実装で、8 ビットのロケールと UTF-8 ロケール をサポートします。これは libutf8-0.6.2.tar.gz より取得できます。

利点:

Plan9 の場合

Unix の一種である Plan9 オペレーティングシステムは、全てのアプリケーションの 文字エンコーディングとして UTF-8 を使用しています。ワイド文字型は `wchar_t' ではなく、`Rune' です。Rob Pike と Howard Trickey が書いたライブラリは ftp://ftp.cdrom.com/pub/netlib/research/9libs/9libs-1.0.tar.gz にあります。Alistair G. Crooks の書いたその他の同様なライブラリは ftp://ftp.cdrom.com/pub/NetBSD/packages/distfiles/libutf-2.10.tar.gz です。これらのライブラリには UTF-8 を扱える正規表現があります。

この API の欠点:

GUI 用には

Qt-2.0 ライブラリ http://www.troll.no/ には、Unicode に完全対応した QString クラス があります。UTF-8 でエンコードされたテキストとの相互変換には、メンバ関数 の QString::utf8 および QString::fromUtf8 を使うことができます。 QString::ascii および QString::latin1 メンバ関数はもはや使うべきではありま せん。

先進的なテキスト操作

これまでに述べたライブラリは、ASCII を扱えるものを Unicode を扱えるよう にしたバージョンです。ここで述べるのは titlecase(単語の始まりを大文字に すること、またはその反対)、句読点と記号の区別、標準的な分かち書き (decomposition)、結合を行うクラス、標準的なソートといった機能を Unicode で扱えるライブラリです。

ucdata-2.3

Mark Leisher の ucdata library http://crl.nmsu.edu/~mleisher/ucdata.html には、文字のプロパティ、 大文字と小文字の変換、分かち書き(decomposition)、結合を行うクラスがあります。

ICU

IBM の Unicode クラス(IBMs Classes for Unicode) http://www.alphaworks.ibm.com/tech/icu/ です。総合的な国際化ライ ブラリで、Unicode の文字列、リソースバンドル、数値のフォーマッタ、日付/ 時間のフォーマッタ、メッセージフォーマッタ、照合などの機能があります。多 くのロケールがサポートされており、Unix と Win32 の間で可搬性がありますが、 そのままでは Linux の libc6 上でしかコンパイルできません(libc5 では駄目です)。

libunicode

Tom Tromey 達による、GNOME libunicode library http://cvs.gnome.org/lxr/source/libunicode/ です。これには文字セッ トのコンバート、文字のプロパティ、分かち書き(decomposition)の機能があり ます。

変換用には

2 種類の変換ライブラリがあります。これは UTF-8 や、 多くの 8 ビット文字セットをサポートしています。

iconv

GNU glibc-2.1.1 に含まれている、Ulrich Drepper による iconv の実装 ftp://ftp.gnu.org/pub/gnu/glibc/glibc-2.1.1.tar.gz

Bruno Haible による可搬性のある iconv ftp://ftp.ilog.fr/pub/Users/haible/gnu/libiconv-1.1.tar.gz

Konstantin Chuguev <joy@urc.ac.ru> による可搬性のある iconv ftp://ftp.urc.ac.ru/pub/local/OS/Unix/converters/iconv-0.4.tar.gz

利点:

librecode

François Pinard の librecode ftp://ftp.gnu.org/pub/gnu/recode/recode-3.5.tar.gz

利点:

欠点:

その他のアプローチ

libutf-8

G. Adam Stanislav <adam@whizkidtech.net>の libutf-8 には UTF-8 エンコードさ れた `FILE*' ストリームとの相互変換を動的に行なういくつかの関数がありま す。 http://www.whizkidtech.net/i18n/libutf-8-1.0.tar.gz

利点:

欠点:

6.2 Java

Java は言語自体が Unicode をサポートします。`char' 型は Unicode 文字を表 し、また `java.lang.String' クラスは Unicode の文字列を扱えます。

Java はどんな Unicode 文字でも、自身のウィンドウシステム AWT を使用して 表示することができます。このために必要なことは、 1. Java のシステムプロパティ "user.language" を適切なものにセットする。 2. /usr/lib/java/lib/font.properties.language フォントセットの 定義を適切なものにセットする。 3. 上記で指定したフォントをインストールする。例えば日本語の文字 を含むテキストを表示するには、日本語のフォントをインストールし、"java - Duser.language=ja ..." で実行します。フォントセットを組み合わせることも できます:西ヨーロッパ、ギリシャ、日本語の文字を同時に表示するには、 "font.properties" (ISO-8859-1 をカバー)、"font.properties.el" (ISO-8859-7 をカバー)、"font.properties.ja" ファイルを組み合わせたものを 作成します。??This is untested??

java.io.DataInput および java.io.DataOutput インターフェースにはそれぞれ、 `readUTF' や `writeUTF' というメソッドがありますが、これらは UTF-8 を使 用しないことに注意してください。これらは変更された UTF-8 を使用します: NUL 文字は 0x00 のかわりに 2 バイトの 0xC0 0x80 としてエンコードされ、末 尾に 0x00 バイトが追加されます。このようにエンコードされるため、文字列は フィールドの長さを持たなくとも、NUL 文字を含むことができます。C では <string.h> の strlen() や strcpy() といった関数でそのような NUL 文 字を含んだ文字列を扱うことができます。

6.3 Lisp

Common Lisp 標準では `base-char' と `character' の 2 種類の文字列型を定 義しています。Unicode をサポートするかどうかは実装に依存します。文字セッ トやエンコーディングを指定するためには、引数として `:external-format' を 指定し、`open' で定義します。

フリーの(訳注:無料ではなく、自由という意味です) Common Lisp の実装では、 CLISP http://clisp.cons.org/ だけが Unicode をサポートしていますが、そ のためには CLISP の 1999年 7月以降のバージョン ftp://clisp.cons.org/pub/lisp/clisp/source/clispsrc.tar.gz が必 要となります。`base-char'型 および `character' 型はどちらも 16-bit Unicode と同等です。ファイル、ソケット、パイプの I/O に使用されるエンコーディン グは `:external-format' 引数で指定することができます。ファイル、ソケット、 パイプの I/O のデフォルトのエンコーディングおよび tty I/O に使用されたエン コーディングはロケールに依存しています。

商用の Common Lisp の実装では、Eclipse http://www.elwood.com/eclipse/eclipse.htm だけが Unicode をサポー トします。 http://www.elwood.com/eclipse/char.htm を参照してください。 `base-char' 型は ISO-8859-1 と同等であり、また `character' 型は全ての Unicode 文字を含むことができます。ファイルの I/O に使用されるエンコーディ ングの指定は `:element-type' および `:external-format' 引数で `open' を指 定することにより可能です。制限事項: 文字属性(character attribute attribute) 関数はロケールに依存しています。ソースおよびコンパイルされたソー スファイルは Unicode の文字列でのリテラルを扱うことができません。

商用の Common Lisp の実装である Allegro CL はまだ Unicode をサポートしま せんが、Erik Naggum が現在作業中です。

6.4 Ada95

Ada95 は Unicode をサポートするためにデザインされました。Ada95 の標準ラ イブラリの機能には、ISO 10646-1 のための特別なデータ型である Wide_Character および Wide_String があります。これらに関連する多数のプロシー ジャや関数も同様です。GNU Ada95 コンパイラ(gnat-3.11 以降)は UTF-8 をワ イド文字の外部エンコーディングとしてサポートします。これにより、UTF-8 を ソースコードとアプリケーションの I/O として使用することができます。アプ リケーションでも使用できるようにするにはファイルをオープンする時に FORM 文字列 に "WCEM=8" をセットし、またソースコードが UTF-8 ならコンパ イラオプション "-gnatW8" を使用します。詳しくは GNAT および Ada95 のリファ レンスマニュアルを参照してください。


次のページ 前のページ 目次へ