Delphi Unicodeワールド パートI:Unicodeとは?なぜ必要なのか?そして、Delphiでどのような作業を行うのか?
この記事は以前EDNサイトに作成されていた記事を転載したものです。
概要
この記事では、DelphiユーザーがUnicodeを使うことにより得られる利点について、またDelphi 2009ではUnicodeがどのように実装されているのかを解説します。
はじめに
インターネットは地理的な障壁を取り除き、ソフトウェアを世界中に配信することを可能にしました。その結果アプリケーションはもはや、純粋なANSIベースの環境で動作するだけにとどまらなくなっています。テキストやデータを送信する標準的な手段として世界中でUnicodeが採用されています。Unicodeは世界中のあらゆる文字をほとんどサポートしているので、Unicodeのテキストはいまやグローバルなテクノロジーエコシステム全体の標準となっています。
Unicodeとは?
Unicodeとは、ほとんど全ての文字を単一のキャラクタセットへと符号化できる「文字の符号化の仕組み」です。Unicodeを使えば、世界中のほぼ全ての文字を含むテキストを管理し表現することが可能になります。Unicodeは、The Unicode Consortiumにより管理され、標準化されています。もっと簡単に言うと、Unicodeは全ての人がお互いの文字を利用することを可能にするシステムです。なんと、クリンゴン語のUnicode版もあります。
この連載記事は、Unicodeとは何なのか、またどのように動作するのかを正確に全て概説するものではありません。その代わり、Delphi 2009でのUnicodeの使い方を説明します。Unicodeの概要をもっと知りたい場合は、Joel Spolsky氏の素晴らしい記事「The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)」があります。これは非常にお薦めです。Joel氏がはっきりと指摘しているように「そんなに難しいものではありません」。このパートIの記事(全3回)では、なぜUnicodeが重要なのか、新しいUnicodeString型をDelphiがどのように実装しているのかを解説します。
なぜUnicodeなのか
Delphi 2009に搭載された多くの新機能の1つに、製品全体が徹底してUnicode化されている点が挙げられます。Delphiのデフォルト文字列は、Unicodeベースの文字列になりました。Delphiはそれ自身がDelphiで構築されているので、そのIDE、コンパイラ、RTLおよびVCLが全てUnicodeに完全対応しています。
DelphiにおけるUnicodeへの移行は自然なものでした。Windows自身がUnicode完全対応なので、Windows向けに構築されたアプリケーションが、デフォルト文字列としてUnicode文字列を使用するのはとても自然なことです。さらに、Delphiユーザーが享受する利益は、単にWindowsと同じ文字列型を利用できるようになる、ということにとどまりません。
UnicodeをサポートすることでさらにDelphiユーザーは大きなチャンスを得られます。いまやDelphiユーザーは、Unicodeデータの読み込み/書き込み/受理/生成/表示/処理が可能になりました。それらが直ちに成果物へと組み込まれるのです。僅かな、または場合によってはまったくコードを変更することなく、あらゆる種類のデータに対応できるようになります。これまではANSIで符号化されたデータだけに制限されていたアプリケーションは、世界中のほとんどの文字を処理するように簡単に修正できます。
Delphiユーザーは、アプリケーションを特別にローカライズしたり国際化することなく、そのアプリケーションをグローバル市場に展開できるようになります。Windows自身が様々なローカライズ版をサポートしており、Delphiアプリケーションは、日本語版/中国語版/ギリシャ語版/ロシア語版のWindowsなど非常に多くのロケールで動作しているPCに対応して動作しなければなりません。あなたが作成したソフトウェアのユーザーは、非ANSIテキストを入力したり、非ANSIベースのパス名を使用するかもしれません。このような場合、ANSIベースのアプリケーションはまず期待通りには動作しません。このような場合でも、Unicode完全対応のDelphiで構築されたWindowsアプリケーションであれば対処可能です。仮にアプリケーションを別の言語に翻訳しないとしても、アプリケーションはエンドユーザーのロケールにかかわらず正しく動作する必要があります。
既存のANSIベースのDelphiアプリケーションにとって、アプリケーションをローカライズしてUnicodeベースの市場へ普及させるチャンスは極めて大きなものです。もしアプリケーションをローカライズしたいのであれば、Delphiを使えば非常に簡単に、しかもデザイン時に可能です。統合翻訳環境(ITE)を使って、IDEの中で翻訳、コンパイル、配布を行えます。もし外部の翻訳サービスが必要な場合には、IDEは、配布可能な外部翻訳環境(ETM)を翻訳者が使えるような形式でプロジェクトをエクスポートすることができます。これらのツールはDelphiとC++Builderの両方のIDEで動作し、アプリケーションのローカライズ工程の管理を円滑・簡単にしてくれます。
世の中はUnicodeベースであり、いまやDelphiユーザーはネイティブかつ本質的な方法でその一員となり得るのです。ですから、もしUnicodeのデータを扱いたい、またはアプリケーションを新興のグローバル市場で販売したいのであれば、Delphi 2009がそれを可能にしてくれます。
用語に関して
Unicodeでは幾つかの新しい用語を利用することなります。例えばUnicodeの世界では、以前の「character」という考え方は、あまり正確ではありません。Unicodeでのより正確な用語は「code point」です。Delphi 2009では、SizeOf(Char) は 2 ですが、話はそれだけでは終わりません。エンコーディングによっては、ある文字が2バイト以上を取ることがあり得るのです。この配列は「サロゲートペア」と呼ばれます。code pointはUnicode.orgによって定義される要素に割り当てられた一意なコードです。大抵の場合これが「character」ですが、常にそうとは限りません。
Unicodeに関連して目にすることになるもう1つの用語は「BOM」または「Byte Order Mark」です。これは、テキストファイルに使用されているエンコーディングの種類を示すために、テキストファイルの先頭に付加されるとても短いプレフィックスです。MSDNにBOMを解説する素晴らしい記事があります。新しいTEncodingクラス(パートIIで解説します)には、指定したエンコーディングのBOMを返すGetPreambleというクラスメソッドがあります。
これまで説明してきた内容を踏まえ、Delphi 2009がどのようにUnicodeベースの文字列を実装しているのか見ていきましょう。
新しいUnicodeString型
Delphi 2009のデフォルトの文字列は、新しいUnicodeString型です。デフォルトでは、このUnicodeString型はWindowsが使用するエンコーディングと同じUTF-16を採用しています。これは従来のデフォルトの型であったAnsiStringとは異なります。これまでDelphiのRTLは、Unicodeのデータを処理するのにWideString型を搭載してきましたが、この型はAnsiString型のような参照カウントを持たず、デフォルトの文字列としてDelphiユーザーが期待する完全な機能は搭載していません。
Delphi 2009では、新しいUnicodeString型が設計され、AnsiStringとWideStringの両方の機能を内蔵しました。UnicodeStringは、Unicodeの文字を持つことができます。(注:AnsiStringおよびWideStringは存続しています) Char型およびPChar型は、それぞれWideChar型とPWideChar型にマッピングされます。また、従来からある様々な文字列型はそのまま残り、開発者が利用してきた全ての型はこれまでと同様に動作します。
しかし、Delphi 2009ではデフォルトのstring型はUnicodeStringに対応します。さらに、デフォルトのChar型はWideCharに、デフォルトのPChar型はPWideCharとなります。
つまり、以下のコードがコンパイラによって宣言されます。
type string = UnicodeString; Char = WideChar; PChar = PWideChar;
UnicodeStringは、それ以外の全ての文字列型に代入可能です。しかし、AnsiStringとUnicodeStringの間での代入には、必要に応じて変換処理が行われます。そのため、UnicodeString型をAnsiString型に代入する際、データの欠落が発生することがあります。つまり、UnicodeStringが上位バイトデータを含んでいる場合には、その文字列をAnsiStringへと変換した際にその上位バイトデータの欠落が発生します。
重要な注意事項として、この新しいUnicodeStringは従来の文字列型と極めて同様な動作を行う点が挙げられます(もちろん、Unicodeのデータを保持できるという重要な例外はあります)。UnicodeStringにあらゆる文字列を追加したり、インデックスを使ってアクセスしたり、「+」記号を使ってUnicodeStringを結合できます。
例えば、UnicodeStringのインスタンスに対し、インデックスを使って文字にアクセスすることができます。以下のコードを見てください。
var MyChar: Char; MyString: string; begin MyString := ‘This is a string’; MyChar := MyString[1]; end;
MyChar変数は、先頭のインデックス位置にある文字「T」を保持します。このコードの機能に変更はありません。同様に、Unicodeのデータを処理する場合には、
var MyChar: Char; MyString: string; begin MyString := ‘世界您好‘; MyChar := MyString[1]; end;
MyChar変数は、先頭のインデックス位置にある文字「世」を保持します。
RTLには、複数のコードページと要素のサイズとの間の変換を明示的に行うことができる関数を用意しています。もし文字配列に対してMove関数を使用している場合には、要素のサイズを予め想定することはできません。
ご想像のとおり、この新しい文字列型は既存のコードに幾らかの影響を与えます。Unicodeではもはや、1つのCharが1Byteではなくなりました。実は、常に1つのCharは2Byteに対応する、というわけでもないのです。その結果、自分のコードに何らかの修正を行わなければならないかもしれません。しかし、私たちはこのような移行がスムーズに行えるよう多大な努力してきました。私たちは、開発者が非常に素早く対応できると確信しています。この連載記事のパートIIとパートIIIでは、UnicodeString型を詳しく解説し、Unicodeに対応したRTLの新しい機能を紹介し、コードの中から探し出したいであろう特定のコーディングパターンについて説明します。この連載記事がUnicodeへの移行をスムーズで簡単なものにしてくれるはずです。
まとめ
デフォルトの文字列としてUnicodeが追加されたことにより、Delphは世界中のほとんど全ての文字やコードページを受け取って処理し、表示することができます。Delph 2009では作成したアプリケーションは、簡単にUnicodeのテキストを受け取って表示し、処理することができます。また、ほとんどのロケールのWindows上でも正しく動作します。Delphiユーザーはこれまで参入が比較的難しかった市場へアプリケーションを展開するために、容易にローカライズや翻訳を行えるようになりました。あなたのDelphiアプリはUnicodeの世界で動作できるようになったのです。
パートIIでは、Unicode文字列の処理を簡単にしてくれるDelphiのランタイムライブラリについて、その修正点やアップデート事項を解説します。