矢沢 久雄

 今回は,Windowsアプリケーションを作成する場合に,文字コードをどのように取り扱えばよいかを説明します。Windowsアプリケーションは様々な開発ツールを使って作成できますが,ここでは主にVisual Basicを使います。Windowsは,現在,シフトJISコードからUnicodeへの転換期にありますが,プログラミングにも,それが如実に現れています。Visual BasicにもWindows自体にも,シフトJISコードとUnicodeの両方を取り扱う仕組みが提供されているのです。

●Unicodeはプログラムで処理しやすい

 WindowsがシフトJISコードからUnicodeへの転換期にあるとは言っても,Windowsにおけるファイルの保存形式の主流は依然としてシフトJISコードのままです。もしもUnicodeでファイルを保存してしまうと,それを読み出せないアプリケーションが多いからです。なんとかUnicodeへの転換を促進させたいものですね。

図1●ファイルはシフトJISコード,プログラムの中ではUnicode
 Visual Basic 5.0以降で作成されたプログラムには,シフトJISコードのファイルをプログラムの内部,すなわちメモリーに読み出すときに,自動的にUnicodeに変換する仕組みが組み込まれました。これとは逆に,メモリーからファイルに書き込むときには,自動的にUnicodeからシフトJISコードに変換されます(図1[拡大表示])。

 なぜVisual Basicは,Unicodeを採用したのでしょう? Unicodeを流行らせるためだと思われるかもしれませんが,そうではありません。シフトJISよりUnicodeの方がプログラムの処理が簡単になるからです。例えば,「123漢字ABC」という文字列の文字数を求めるとしましょう。シフトJISコードのままで処理する場合は,「漢」と「字」の部分が漢字であることを判別するプログラムが必要になります。この文字列は,シフトJISコードで10バイトになりますが,数字と英字は1文字1バイト,漢字は1文字2バイトなので,全体で8文字になります。

 同じ文字列をUnicodeで処理してみましょう。Unicode(UTF-16)では,数字,英字,漢字にかかわりなく,1文字は2バイトです。したがって,「123漢字ABC」という文字列は,16バイトになります。16バイトなら,16÷2=8文字と簡単に計算できるのです。ただし現在,Unicodeは1文字に4バイトを割り当てる仕組みを導入する方向に向かっています。将来,この仕組みが使われ始めると,1文字を2バイトで表すことの便利さは薄れてしまう可能性があります。

●文字列の長さとバイト数を求めてみよう

 Visual Basicが提供している命令の中で,文字列の文字数(長さ)を求めるのはLen関数です。Len関数は,パラメータに与えられた文字列をUnicodeとみなして,その文字数を返します。LenB関数という命令もあります。LenB関数は,文字列のバイト数を返すものです。

図2●リスト1の実行結果
 リスト1は,シフトJISコードで「123漢字ABC」という文字列が記録されたファイル(MyFile.txt)の内容をメモリー(変数s)に読み出し,その文字数とバイト数を表示するプログラムです。実行結果は,図2のようになります。ファイルのサイズは,10バイトですが,プログラムの中に取り込まれるときにUnicodeに変換されて16バイトになっていることが分かるでしょう。

●文字と文字コードの変換

 Visual Basicで,パラメータに与えられた文字の文字コードを返す命令は,Asc関数です。文字コードに対応する文字を返すのは,Chr関数です。これらの関数を使えば,文字と文字コードを相互に変換するアプリケーションが作成できます。ところで,Asc関数が返す文字コードや,Chr関数のパラメータに与える文字コードの種類は,何だと思われますか? Visual Basicは,内部的にUnicodeを採用しているので,Unicodeとすべきでしょう。ところが,実際には,どちらもシフトJISコードなのです。このあたりが少々ややこしいかもしれません。

図3●リスト2の実行結果
 実際に,「漢」という漢字を使って確かめてみましょう。「漢」のシフトJISコードは8ABFHで,Unicodeは6F22Hです。リスト2は,Asc関数のパラメータに「漢」を与えた場合の戻り値と,Chr関数のパラメータに8ABFHと6F22H(Visual Basicでは,数値の先頭に&Hを付けて16進数を表します)を与えた場合の戻り値を表示するプログラムです。Hex関数は,数値を16進数に変換するものです。図3に示した実行結果を見ると,確かにAsc関数やChr関数がシフトJISコードを対象としていることがわかります。

 メモリー上ではUnicodeで文字を処理しているVisual Basicであっても,プログラマが文字コードを指定する場合にシフトJISコードが使われるのはなぜでしょう? これは,あくまで筆者の推測ですが,ファイルの保存形式の主流がシフトJISであるからには,プログラマが慣れ親しんでいる文字コードは,シフトJISコードであると(Visual Basicの開発者が)考えたからでしょう。

 ただし,Visual Basicは,Unicode版のAsc関数やChr関数として,AscW関数とChrW関数も提供しています。これらの関数名の末尾のWは,Wide文字(2バイト文字)を表しています。Unicodeが十分に普及すれば,Asc関数やChr関数の方がUnicode用で,シフトJISコード用のAscA関数やCharA関数(末尾のAは,ANSIの頭文字を表します)が提供されるようになるかもしれませんね。

●Win32 APIもシフトJISコードとUnicodeの両方に対応している

 Visual Basicに限らず,Visual C++,Delphi,JBuilderなど,どのような開発ツールで作成されているとしても,Windowsアプリケーションである以上は,最終的に必ずWin32 APIを呼び出すことになります。Win32 APIとは,WindowsがOSとしてアプリケーションに提供するシステム・コールのことです。APIは,Application Programming Interfaceの略です。Win32 APIの実体は,様々な機能を持つ関数が収録されたDLLファイルとなっています。

 Win32 APIの中には,文字列を取り扱う関数もあります。例えば,TextOut関数は,画面に文字列を表示します。それでは,TextOut関数は,Unicode用なのでしょうか? それともシフトJISコード用なのでしょうか? ヒントは「Windows 95/98/Meは,シフトJISコードを採用したOSであり,Windows NT/2000は,Unicodeを採用したOSである」です…。

図4●Win32 APIには,シフトJISコード用とUnicode用の関数がある
 この問題の答えは,「両方である」が正解です。シフトJISコードを採用していた初期の16ビットWindowsの時代から,画面に文字列を表示するAPIの名前はTextOutでした。ベテランのWindowsプログラマは,TextOutという名前に慣れ親しんでいます。現在は,シフトJISコードを使うWindowsとUnicodeを使うWindowsが存在しています。そこで,32ビットWindowsからは,Unicode用のTextOutW関数とシフトJISコード用のTextOutA関数の2つを用意しておいて,プログラマがTextOut関数を呼び出すと,環境に応じてTextOutW関数またはTextOutA関数の呼び出しに自動的に変更してくれるようになっているのです。文字列を表示するのに2つの関数が提供されているのは無駄なことのように思われるかもしれませんが,シフトJISコードからUnicodeへの転換期なのですから仕方ありません(図4[拡大表示])。

 なお,TextOutW関数の末尾のWはWide文字を表し,TextOutA関数の末尾のAはANSIを表します。アメリカ生まれのWindowsでは,文字コードはANSI(ASCIIを制定したのがANSIなので,ANSIはASCIIを意味します)からUnicodeへの転換期なのです。

●新しいプログラミング言語は,Unicodeを採用している

 Visual Basicの話ばかりしてきましたので,他のプログラミング言語にも目を向けてみましょう。皆さんに知っていただきたいことは,新しいプログラミング言語では,続々とUnicodeが採用されているということです。その好例として,「C言語一族」のプログラミング言語が挙げられます。「C言語一族」のプログラミング言語とは,C言語,C++,Java,C#のことです。

 1975年生まれのC言語では,文字をcharというデータ型で表すようになっています。charには,1バイトのデータを格納できます。C言語が登場したときには,ASCIIしかなかったので,これで問題ありませんでした。

 1980年生まれのC++は,C言語にオブジェクト指向プログラミングの機能を追加したものです。C++にも1バイトのchar型がありますが,それに加えて2バイトのwchar_t型もあります。1バイト文字と2バイト文字が混在する時代になったのです。Windows用のC++であるVisual C++には,TCHAR型というものもあります。TCHAR型は,Unicode環境と指定した場合,wchar_t型と同じものです。

 1995年生まれのJavaは,C++をベースに開発されたインターネット・プログラミングのためのプログラミング言語です。Javaにもchar型がありますが,2バイトのデータを格納するものとなっています。Javaは,内部的にUnicodeで文字を処理しているからです。インターネットとともにUnicode時代が到来したのです。

図5●C言語一族に見る文字コードの変遷
 2000年生まれのC#は,マイクロソフトの次世代インターネット・プラットフォームである.NET(ドットネット)対応アプリケーションを作成するためのプログラミング言語です。C#もC++をベースとしていますが,Javaと同様に,char型が2バイトとなっています(図5[拡大表示])。

 この講座の読者の中には,プログラミング経験のない方もいることと思いますが,文字コードの違いがプログラムに大きな影響を与えることをご理解いただけたことと思います。

 次回は,文字コードのダンプ・リストを見たり,文字コードを変換したり,機種依存文字をチェックしてくれる便利なフリーウエアの数々を紹介します。お楽しみに!

(→「第5回 フリー・ソフトを活用しよう」を読む)