JScript.NET で読み込んだファイルの文字コードが UTF-8 か Shift-JIS か判定する
JScript.NET で読み込んだテキストファイルの文字コードを判別したかった。
こちらのサイトで、Jcode.pm という Perl 製の有名な文字コード判定スクリプトを VB.NET と C# に移植していた。
元のソースは JIS や EUC も判定できるのだが、今回はコレをベースに、「テキストファイルが Shift-JIS か UTF-8 のどちらか」を判別する簡易版を JScript.NET で作ってみた。このコード部分だけなら JScript.NET 特有の処理は含んでいないので、そのまま JavaScript としても利用できると思われる。
ドキュメンテーションコメント部分は、Closure Compiler で使えるアノテーションコメントに沿って書いてみた。
/**
* 文字コードを Shift-JIS か UTF-8 か判定する
*
* @param {Array.<Byte>} bytes テキストファイルのバイト配列
* @return {String} UTF-8 と判定したら "utf-8"、Shift-JIS と判定したら "shift-jis" を返す
*/
function getCode(bytes) {
var len = bytes.Length;
if(len < 2) {
// 短すぎると判別不可能、UTF-8 とみなすことにする
return "utf-8";
}
else if((bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF)) {
// BOM 付き UTF-8
return "utf-8";
}
var sjis = 0;
for(var i = 0; i < len - 2; i++) {
var b1 = bytes(i);
var b2 = bytes(i + 1);
if( ( (0x81 <= b1 && b1 <= 0x9F) || (0xE0 <= b1 && b1 <= 0xFC) ) &&
( (0x40 <= b2 && b2 <= 0x7E) || (0x80 <= b2 && b2 <= 0xFC) ) ) {
sjis += 2;
i++;
}
}
var utf8 = 0;
for(var i = 0; i < len - 2; i++) {
var b1 = bytes(i);
var b2 = bytes(i + 1);
if( (0xC0 <= b1 && b1 <= 0xDF) &&
(0x80 <= b2 && b2 <= 0xBF) ) {
utf8 += 2;
i++;
}
else if(i < len - 2) {
var b3 = bytes(i + 2);
if( (0xE0 <= b1 && b1 <= 0xEF) &&
(0x80 <= b2 && b2 <= 0xBF) &&
(0x80 <= b3 && b3 <= 0xBF) ) {
utf8 += 3;
i += 2;
}
}
}
if(sjis > utf8) {
return "shift-jis";
}
else if(utf8 > sjis) {
return "utf-8";
}
// 不明・UTF-8 とみなすことにする
return "utf-8";
}
Jcode.pm のことはこのスクリプトを作る時に初めて知ったのだが、どうやらテキストデータのバイト配列から「Shift-JIS っぽい並び」や「UTF-8 っぽい並び」を見付けてはポイントを加算し、一番ポイントが高い文字コード種別を返しているようだ。
こうして作った getCode()
関数は以下のように使う。
/**
* テキストファイルの文字コードを判定した上でテキストを読み込み、
* CR+LF で改行した文字列を返却する
*
* @param {String} filePathStr 読み込みたいテキストファイルのフルパス
* @return {String} CR+LF で改行したテキストファイルの文字列
*/
function readTextFile(filePathStr) {
// 引数のテキストファイルを読み込み、文字コードを判定する (getCode() を使用)
var enc = getCode(System.IO.File.ReadAllBytes(filePathStr));
// 変数 enc に判定した文字コードが入るため、これを利用して改めてテキストファイルを読み込む
var stream = new StreamReader(filePathStr, Encoding.GetEncoding(enc));
// テキストを保持する変数
var text = "";
// 1行ずつテキストを読み込み、改行コードを付与していく
while(stream.Peek() > -1) {
text += stream.ReadLine() + "\r\n";
}
stream.Close();
return text;
}
この関数では、引数にテキストファイルのパスをもらい、さきほどの getCode()
で文字コードを判定している。判定した文字コード種別を使用して Stream で読み込んだら、改行コードを CR+LF に統一して文字列で返却している。