Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume I/8-2
8-2 文字
ハンドヘルドがサポートする言語によって、Palm OS は文字を単一バイトエンコーディングまたはマルチバイトエンコーディングを用いてエンコードします。実行時までどの文字エンコーディングが使用されているかを知ることはできないため、文字のサイズに関してなんらかの仮定をするべきではありません。
ほとんどの場合、どの文字エンコーディングが使用されているかをアプリケーションが知る必要はありません。そして実際には、エンコーディングや文字サイズについてなんらかの仮定をするべきではありません。そうするかわりに、テキストマネージャを用いて文字を操作するべきです。このセクションでは文字を正しく扱う方法について説明します。以下のトピックがあります。
- 文字変数の宣言
- 文字定数の使用
- 欠落文字と不正文字
- 文字属性の取得
- 仮想文字
- 文字エンコーディングの取得
文字変数の宣言
全ての文字変数は WChar 型で宣言して下さい。WChar は符号無しの 16 ビット変数で、全てのエンコーディングの文字を格納できます。Char は使用しないで下さい。Char は 8 ビット変数であり、大きな文字エンコーディングに対応できません。Char を使用すべきなのは、古い Palm OS 関数にパラメータを渡す時だけです.
WChar ch; // 正しい。16 ビット文字。 Char ch; // 誤り。 8 ビット文字。
keyDownEvent を通して入力文字を受信する場合、WChar 値を受け取ることになります( つまり、data.keyDown.chr フィールドは WChar 型です )。
文字変数は WChar として宣言しますが、たとえマルチバイト文字を含んでいたとしても文字列のための変数は Char* で宣言します。文字列に関しては 「 8-3 文字列 」を参照して下さい。
文字定数の使用
文字定数はいくつかのヘッダファイルで定義されています。ヘッダファイル Chars.h では、エンコーディングに関わらず全てのシステムでサポートされることが保証される文字を含んでいます。その他のヘッダファイルはそれぞれの文字エンコーディングごとに存在し、そのエンコーディングに固有の文字を含んでいます。文字エンコーディング固有のヘッダファイルはデフォルトでは PalmOS.h にはインクルードされません。なぜなら、それらのヘッダファイルは全てのシステムで利用できるわけではない文字を定義しているからです。
コンパイラが文字エンコーディングの問題を簡単に発見できるように、文字変数にダイレクトに値を代入するかわりに、各ヘッダファイルで定義されている文字定数を使うようにします。例えば、以下の文がコードに含まれていたとします。
WChar ch = 'a'; // WRONG! Don’t use. 訳注:原著では、英小文字 a の上に小さな丸がついた ラテン文字(というのでしょうか)になっています。
この文は Latin システムでは動作しますが、アジア言語のシステムでは文字が存在しないために問題が発生するでしょう。かわりに以下のように値を代入すれば、
WChar ch = chrSmall_A_RingAbove;
chrSmall_A_RingAbove 定数はデフォルトではインクルードされない CharLatin.h で定義されているため、コンパイル時点で問題に気付くでしょう。
欠落文字と不正文字
アプリケーションのテスト中に、白抜きの矩形や網掛けの矩形、あるいは灰色の正方形が画面に表示されるかもしれません。それは欠落文字を表しています。
欠落文字というのは、文字エンコーディングとしては正当ですが現在のフォントで表示できないものを指します。この場合、コードには問題はなく、フォントの選択を誤っています。システムは欠落している単一バイトの矩形の位置に白抜きの矩形を表示します( 図 8.1 参照 )。
図 8.1 欠落文字
マルチバイト文字エンコーディングでは、文字は上記のように欠落している場合もありますが、不正である場合もあります。単一バイト文字エンコーディングでは、数値とそれが表す文字は1対1に対応していますが、マルチバイト文字エンコーディングにはあてはまりません。マルチバイト文字エンコーディングでは、表現すべき文字よりも多くの値が存在します。従って、文字変数が不正文字 ―― つまり実際には文字でない値 ―― を含んでしまうことがあります。
不正文字を表示するよう求められると、システムは最初の不正なバイトに対して白抜きの矩形を表示し、次に2バイト目を処理します。従って、表示される次の文字とそれに続いて表示されるテキストは、表示されるべきものではない可能性があります。コードを以下の観点でチェックして下さい。
- 文字を切り捨てていないか。マルチバイト文字の途中で文字列を切り捨てている可能性があります。
- あるエンコーディングの文字列を別のエンコーディングの文字列に追加していないか。
- 文字変数に対して、不正な文字値になるような演算をしていないか。
- 文字列ポインタに対して、結果としてマルチバイト文字の途中を指すことになるような演算をしていないか。詳細は“文字列ポインタの操作”を参照して下さい。
- 文字が常に単一バイト幅であると仮定していないか。
テキストマネージャ関数の TxtCharIsValid( TxtGlueCharIsValid )を使って文字が不正でないかどうかをチェックして下さい。
文字属性の取得
テキストマネージャは文字の属性を取得するための関数を定義しています。ここで属性とは、文字が英数字であるかどうか、などです。これらの関数は、サイズやめてエンコーディングに関わらずどんな文字に対しても使用できます。また、文字はエンコーディングに特有の属性も持っています。そのような属性を取得するための関数は各エンコーディング個別のヘッダファイルで定義されています。
- WARNING!
- 古いバージョンの Palm OS では、ヘッダファイル CharAttr.h で IsAscii のような文字属性マクロを定義していました。これらのマクロを2バイト文字に対して使用すると正しくない結果をもたらします。CharAttr.h のマクロではなく、テキストマネージャのマクロを使用して下さい。
仮想文字
仮想文字は画面に表示されない文字で、オペレーティングシステムの特殊なイベント ── 例えばバッテリ残量の警告表示やキーボードダイアログの表示など ── の契機となるものです。仮想文字はデータ内に存在してはいけませんし、画面に表示してもいけません。
Palm は文字コード 256( 10進 )以上を仮想文字として使用します。この範囲は、“実際の”文字(つまり画面上に表示される文字)の範囲と重なる場合があります。keyDownEvent はイベントレコードの command ビットをセットすることで、仮想文字と実際の文字を区別します。
ハードキーを含む仮想文字をチェックするベストな方法は、PalmOSGlue ライブラリで定義されている TxtGlueCharIsVirtual 関数を使用することです。リスト 8.1 を参照して下さい。
リスト 8.1 仮想文字のチェック
if (TxtGlueCharIsVirtual (eventP->data.keyDown.modifiers, eventP->data.keyDown.chr)) { if (TxtCharIsHardKey (event->data.keyDown.modifiers, event->data.keyDown.chr)) { // Handle hard key virtual character. } else { // Handle standard virtual character. } } else { // Handle regular character. }
文字エンコーディングの取得
場合によっては、どの文字エンコーディングが使用されているかを調べる必要があります。例えば、ヨーロッパ向けのハンドヘルドの場合にアプリケーションが特殊なテキスト操作をする必要がある場合などです。FtrGet 関数を使えばシステムフィーチャから文字エンコーディングを取得することができます。リスト 8.2 を参照して下さい。
リスト 8.2 文字エンコーディングの取得
UInt32 encoding; Char* encodingName; if (FtrGet(sysFtrCreator, sysFtrNumEncoding, &encoding) != 0) encoding = charEncodingPalmLatin; //default encoding if (encoding == charEncodingPalmSJIS) { // encoding for Palm Shift-JIS } else if (encoding == charEncodingPalmLatin) { // extension of ISO Latin 1 } // The following Text Manager function returns the // official name of the encoding as required by // Internet applications. encodingName = TxtGlueEncodingName(encoding);