miau's blog?

コンソール(cmd.exe)の文字コードを UTF-8 に

最近だとソースコードや DB を UTF-8 で統一するのが当たり前になってきてますが、日本語版の Windows は cmd.exe で Shift_JIS(Windows-31J)以外でエンコードされた文字を出力すると文字化けしてしまいます。

この対応について、半端ではありますがいくつか調べたのでそのお話。




■対応方法

○chcp 使う→これだけではダメ。

去年の頭の時点で一般的にいわれていた対策は「chcp 65001」にするというもの。

chcp 65001

でもこれってうまくいかないんですよね。「これは UTF-8 ですよ。」という内容のテキストファイルを出力すると、こんな感じ。

chcp_bake1
(ラスタフォント。マルチバイトが 1 バイトずつ認識されてる。)

chcp_bake2
(Lucida Console。文字認識はうまくいってるけどフォントが該当文字を持っていない。)

chcp_bake3
(Win7 上でのラスタフォント。元々 3 バイトなのに 2 バイトになってる???)

さらに環境によっては dir で日本語表示したときに cmd.exe が落ちることも。

○フォントを指定する

chcp だけではダメで、フォントも指定する必要があるそうで。その指定も色々試して失敗してたんだけど、どうもこの方法が一番まともに動作する様子。

へっぽこSE奮闘記 - コマンドプロンプトのフォントを変更する方法

REG コマンドでやるなら、こんな感じ。

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" /v "0." /t "REG_SZ" /d "MS Gothic"

chcp 65001 の状態でフォントを指定してしまっていると反映されないので、コマンドプロンプトを一旦閉じたり、再起動したりするといいかもしれません。

○残る問題点

そもそも cmd.exe の動作が不安定なので UTF-8 を使う場合特有の問題かどうかもわからないのですが、文字の描画位置がずれたりもします。この現象については以下のページが詳しいです。

コマンドプロンプトの謎 - ××××Diary

■レジストリ設定の意味は?

○疑問

それにしても、

値の名前:0. (ゼロ ドット)

ってどういう意味?「こうすればできますよ」って情報はそれだけでも嬉しいんだけど、理屈がわからないと気持ち悪い。

○公式情報

ということで調べてみると・・・

Necessary criteria for fonts to be available in a command window

MS 公式では、「コンソールで使えるフォントの選択肢を増やすには 00、000 と 0 を増やして項目を追加してね」って書いてある。(その他指定可能なフォントについても細かい情報あり。)ドットってどこから出てきたの?

○オープンソース万歳

そういえば Windows 2000 の流出コードってあったなー、ということでちょっとのぞいてみる。

断片的なコード(定数の定義が見つからないこともあったり)だし、どういうタイミングで呼ばれる処理かもわからないけど、

・private\shell\shell32\dbcs.c
 →上記のレジストリキーが定数定義されている
・private\ntos\w32\ntcon\server\dbcs.c
 →該当キーの操作をしている箇所あり
・private\windows\shell\control\console\dbcs.c
 →似たような処理があるけど 16 bit 版?

という感じ。

コードページの変換には簡易版の atoi っぽい自作関数が使われていて、
・文字列を先頭から走査
・数字([0-9])であればバッファを x 10 してその値を加算
・数字以外が来たら終了
というような処理になってる。このロジックで 0 と判定される文字列だったらなんでもいいので、「0.」でも「00」でもいいし、おそらく「0hoge」なんかでもうまくいくんでしょう。

○どうするのがベスト?

こちらの方が書いているように、ほかのコードページについては、.1、.2 のように増やしていくのが見やすい気がします。

cmd.exe(コマンド プロンプト)のフォントを変更する | Windows - P-SOC

ちなみに reg コマンドもこの方のページを参考にしました。

cmd.exe(コマンド プロンプト)のフォントを変更する(reg コマンド編) | Windows - P-SOC

■その他試したけどダメだったこと

それぞれの反映のタイミングがよくわからない&なにか設定がキャッシュされている様子なので、検証方法が悪いだけかもしれませんが・・・以下ではダメでした。

○UTF-8 のフォントを指定する

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" /v "65001" /t "REG_SZ" /d "MS Gothic"

→結局一覧に出てこないので意味がない?

○デフォルトである Lucida Console を変えてみる

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" /v "0" /t "REG_SZ" /d "MS Gothic"

→候補から Lucida Console が消えただけ。この方法でうまくいったこともあるんだけど、\ がウォン表記になってたりで死ぬほど怪しかったり。

○「MS Gothic」を「MS ゴシック」だとか「*MS ゴシック」に変えてみる

reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont"

の一覧に出てくるフォントを使うのが礼儀らしいけど、コードページ 932 や Web 上の情報では結構日本語表記になっていたので試してみたりも。
→効果なし。

■その他参考ページ等

INFO: SetConsoleOutputCP Only Effective with Unicode Fonts

ラスタフォントについては chcp は効かないとか書いてる気がする。あと Lucida Console しか使えないとか??

コマンドプロンプトの文字コードを変更する。 - 趣味でやってます。

コードページの一覧あり。EUC-JP は chcp 20932、ISO-2022-JP(JIS)は chcp 50222 or 50220 ってところ。

コマンドプロンプトでUTF-8の文字を表示する。 - Perl入門〜サンプルコードによるPerl入門〜

cmd.exe の起動時に chcp を呼び出してオプションで文字コード指定する方法。常に UTF-8 を使うようなケースでは役に立つかも。


その他フォントリンクで解決する方法もある気がする。ラスタフォントには指定できないけど、Lucida Console には設定できるかも?
posted at 07:06:53 on 2009-03-23 by miau - Category: General No Trackbacks - Permalink

TrackBack

このエントリにトラックバックはありません
現在トラックバックは受け付けていません。

Comments

No comments yet

Add Comments

現在コメントは受け付けていません。
お手数ですが、 こちら のコメント欄にでも記載していただければと思います。