2009-12-2[水] Unicodeコンソール関係の適当メモ

unix/linux系なら、過去互換気にしなければ普通utf8環境.

winだと一応(たぶんnt系. 少なくともw2k以降の) dos窓にて

chcp 65001

とすれば、文字エンコードをutf8にした環境に (あるいは chcp 65000 とすれば utf7環境に) はなる.

ただし、文字フォントが日本語ファイル未対応なので、そのままだと文字化けする. こちらのサイト等みて レジストリ設定すれば日本語表示可能になる.
("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" に名前 "0." で文字列値"MSゴシック" (か何か日本語フォント名)を設定. cp932のままのdos窓のプロパティでMS ゴシックを選択、そのあとchcp 65001で切替. ただ何度か失敗するかも? 一度os再起動したほうが無難のよう)


で表示はなんとかなるが、問題は、日本語入力(IME)が使えない. 日本語環境とみなされていないよう. CP932でのみ判定してるのか、DOS標準コマンドのヘルプが英語になる. (当然sjis依存ツールは文字化けなんで、それに比べれば十分マシだけど).

os標準の入力(MS-IME)が出来れば、もっとutf8コンソール普及するかも? (Win7は未確認だけどたぶん)


utf8環境での、言語(国)の判定は win32apiだと

LCID GetUserDefaultLCID();

で判定可能。LCIDでの日本は1041. (他にも何か判定方法はあったような気はするけど、これが楽かも.

C標準ライブラリの場合 setlocaleはあれど getlocale なんてのはないので標準的な判定はなし. (そもそもsetlocaleの引数/戻値はosによって設定する値が違うので、移植性を考えよう無い)
追記: os環境の情報ではないけれど、setloacleの現在値については、setlocale(type,NULL)で情報取得できるので getlocale 相応があるといえばある状態.

unix系だと環境変数LANG みれば... iconv とか gettext とか用いるが普通?


オーソドックスなコンパイラなら、ソース中のマルチバイト文字(というかSJIS)対応をするオプションを立てずにutf8でソース書けばok (のはず).
がvcは不明. vc はソースの文字エンコードにかかわらず 実行バイナリに対してはcharはマルチバイト文字, wchar_tはunicode(utf16)に変換されるが、 char型の文字エンコードを切り替える方法がわからない. cl のオプションには見当たらず (プロジェクトのプロパティのは単にライブラリヘッダに対するdefine). コンソールをus(chcp 437)やutf8(chcp 65001)にした状態でclでコンパイルしてもexeはsjis.


winでsjisコンソールのままプログラム内部の処理をutf8にした場合 問題になるのは

  • コマンドライン引数
  • コンソールに対する入出力.主に標準入出力、標準エラー出力(stdin,stdout,stderr)

あたりか. もちろん通常プログラムが扱うテキストファイルはutf8でいいとして.

このためにCランタイムやライブラリを修正するとしたら、 コマンドライン引数はW系文字列で取得してutf8化すればすむだろうが、 対コンソール入出力についてはどうする?

標準入出力関係だけならば、fileno(fp) が 0,1,2 なら標準入出力エラー出力だろうで、 決めうち変換する? (freopenとかやられると不味いそう?)

win系コンパイラ(vc,mingw,dm,bcc,watcom)ならio.hにfileno(),_get_osfhandle()があるだろうで、

FILE   fp    = stdout; //fopen("hoge","rb");
int    fno   = fileno(fp);
HANDLE hFile = _get_osfhandle(fno);
DWORD  type  = GetFileType(hFile);

として type == FILE_TYPE_CHAR ならコンソールだろうとして、扱えばいいか (LPTは微妙)

コンソールのコードページ判定は

GetConsoleCP();        // コンソール入力のコードページ
GetConsoleOutputCP();  // コンソール出力のコードページ

でできそうなので、utf8(65001)以外ならその文字エンコードに変換してから出力すれば... FILE関係, io.hな_open関係 にごっそり手を入れる必要があるのでやってられないけど(可能性としては).


utf8化することでSJISに対し

  • 使える文字がSJISより増える. 多言語対応が楽.
  • \ (0x5c)問題が回避できる

が、SJIS(DBC)だと基本的に 1バイト文字は半角、2バイト文字は全角、になるので 固定フォントによるテキスト表示をバイト数で桁あわせできて楽だったのが、utf8だと、単純にできなくなる.
mbc,utf8未対応の(海外)ソフトを日本語対応するならばmbc(sjis)で行うほうが桁あわせやバッファサイズ調整の手間は少ないだろう. (変わりに\問題が... なんでeucjpのほうが)

ただ日本語フォントかつ SJIS範囲の文字のみを前提に決め内するならば,

  • 0x00~0x7f, 0xff60~0xff9f(半角カナ) を半角文字(1文字幅)
  • 以外を全角文字(2文字幅)

で扱うのでもいいかも.

欧州系の文字の場合半角扱いのフォントのほうが多いだろうけど、 JIS第一水準のギリシア・ロシア文字あたりは、日本系のフォントなら全角だったりして、その判定は 結局フォント別に判定が必要になってくるかも...なので、あくまでJIS漢字の範囲を前提にするならばこの程度でよいかも、と.


vcの場合fopen("hoge", "rb,ccs=UTF8")やopen("hoge", _O_RDONLY|_O_UTF8); のようにオープン時にutf8(同様にutf16)指定することが可能なよう.



D言語環境とか、mingwでの文字列をutf8ベースにする場合とかを考えてた. mingwの場合、msvcrt.dll系のdllを使うので、ライブラリ関数一部差替は ヘッダ弄ってimportやめてリンクする形できるだろうが... あるいは newlib 使ったバージョンとかはないのだろうか... とか何かと大事な作業に化けてしまうので、思うだけで終わってしまったのでした.