日本語文字コードの判別

文字コードの判別はバイナリデータの難しい処理というイメージがあったけど、そこそこの精度でいいなら意外と単純だった。
今回の方針は、半角カナは無視、UTF-8の優先度高め、という方針。

各ESC(0x1B〜)が出た場合はISO-2022-JP(確定)
第1バイトで指定された長さ以下の場合は他コード(非UTF-8確定)
半角カナを考える必要がなければ0x80<->0xA0をチェックしてこの範囲がでればSJIS

http://kasumi.sakura.ne.jp/~gm/gpj/dev/tips/other/kanji.shtml

コード本体

String.prototype.uconv = function(charset){
  var u = Components.classes['@mozilla.org/intl/scriptableunicodeconverter']
       .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
  u.charset = charset;
  return u;
}
String.prototype.convTo = function(charset){
  return this.uconv(charset||'UTF-8').ConvertFromUnicode(this);
}
String.prototype.convFrom = function(charset){
  return this.uconv(charset||this.guess()).ConvertToUnicode(this);
}
String.prototype.guess = function(){
  if(this.match(/\x1B/)) return 'ISO-2022-JP';
  try{this.convFrom('UTF-8'); return 'UTF-8'}
  catch(e){return this.match(/[\x80-\xA0]/) ? 'Shift_JIS' : 'EUC-JP'}
}

テスト

>>> 'あ'.convTo('UTF-8').guess()
"UTF-8"
>>> 'あ'.convTo('ISO-2022-JP').guess()
"ISO-2022-JP"
>>> 'あ'.convTo('Shift_JIS').guess()
"Shift_JIS"
>>> 'あ'.convTo('EUC-JP').guess()
"EUC-JP"

おぼえがき

ConvertToUnicodeはUTF-8からの変換時に規格外のデータを与えると例外を発生するが、
EUC-JP,Shift_JIS,ISO-2022-JPからの変換では変な文字になるだけで例外は発生しない。
ConvertToUnicodeはUTF-8からの変換時にESC(=0x1B)が入っていても例外を発生しない。