WindowsのコマンドプロンプトとUnicode

(これ、ちょっと内容が誤解を招きそうなので、すこし補足を。"/U"スイッチは"cmd.exe"の内部コマンドにかかわるもの。)

Windowsコマンドプロンプト文字コードについて。こまごまと。
下のコマンドを試した環境は Windows XP x64 SP2 と Windows XP x86 SP3 だ。Vistaとか7だったら、おなじように動くと思う。

リダイレクト、パイプと文字コード

リダイレクトやパイプ時の標準出力なんかの文字コードは、デフォルトでは、コマンドプロンプトのコードページになる。Unicode(UTF16-LE)にすることもできる。
cmd.exeのスイッチ"/A"、"/U"で切り替えられる。
"/A"はANSI(デフォルト)、"/U"はUnicodeとなる。

コマンドプロンプトで以下のコマンドを実行する。"hoge.txt"はSJIS(というかCP932)でも、Unicode(UTF16-LE、先頭にBOMが必要)*1でもかまわない。
中身は「こんにちは」とか適当に日本語文字列が入っているとする。

type hoge.txt > a.txt

日本語Windowsだと、"a.txt"は、まずSJIS(正確にはCP932か)のテキストになる。

cmd /U /c type hoge.txt > a.txt

とすると、"a.txt"はUnicodeのテキストファイルになる。ただし、先頭にBOMは付かない*2。確認のためエディターなどで開いた場合、BOMがないから文字コードの判定に失敗して文字化けして表示される可能性がある。たとえばメモ帳だと判別に失敗する。Unicodeのテキストだと指定して開かないと、きちんと開いてくれない。

UTF16-LEのBOMだけのファイル("bom.txt"とする)を作って下のようにすればBOM付きのファイルができる。なんか簡潔じゃない、汚い書き方だなあとおもうので、うまいやり方があれば知りたいところ。ただまあ、これでtypeコマンドとちょっとしたもので、CP932のファイルからUnicodeのテキストファイルへの変換ができる。

copy /B /Y bom.txt a.txt & cmd /U /c type hoge.txt >> a.txt

UnicodeからCP932への変換は、typeがUnicodeテキストを開けるから、下のコマンドでできる。"hoge.txt"は先頭にBOMありのUTF16-LEテキストファイルとする。できあがる"a.txt"はCP932のテキストファイルだ。もちろん、Unicodeでないと表現できない文字は'?'とかに置き換わる(近い別の文字に変わるものもある)。

type hoge.txt > a.txt

コマンドプロンプトのコードページを変更するchcpコマンドと組み合わせると、UTF8とUTF16の変換なんかもできる。でも、ちょっと面倒くさい。

これは、[バッチファイルを Unicode や UTF-8 で書く。: Windows Script Programming]というページを参考にした。

UTF8→UTF16は下のようにすればできる。

start /min /wait cmd /c chcp 65001 ^& cmd /U /c type hoge8.txt ^> hoge16.txt

ただ、参考にさせてもらったページでも気をつけないといけないことなんだけど、UTF8のテキストファイルにBOMがあると、UTF16のファイルにそのままBOMもはき出してくれる。けれども、UTF8のテキストファイルにBOMがないと、UTF16のファイルにもBOMは出力されない。上でできたhoge16.txtをさらにtypeで読み込んで――と参考元ページと同じことがしたい場合は、UTF8のテキストファイルをBOMありで保存しておかないといけない。

UTF16→UTF8は下のようにすればできる。

start /min /wait cmd /c chcp 65001 ^& cmd /c type hoge16.txt ^> hoge8.txt

このとき、hoge16.txtは先頭にBOMがあるUTF16-LEのファイルである必要があるが、できあがるUTF8のファイルからBOMはたたき落とされる。

それを使った応用みたいなのが、[バッチファイルだけで、UnicodeLE や UTF-8 の BOM を除去する。: Windows Script Programming]にある。よく考えつくなあ……と思う。

"cmd.exe"の"/U"スイッチにを知ったページを参考サイトとして書いておきたいのだけれども、メモがどっかいった。見つかったら追記しておこうと思う。

*1:開けるのはUTF16-LEのみで、BOM付いててもUTF16-BEはだめ。

*2:BOM出力をしてよい状況の判別はむずかしかろうしね……。いろんな状況があるだろうから。