外部ファイルやレガシーシステムのデータを扱うとき、指定した文字エンコーディングがブラウザでサポートされているかを事前に判定したい場面があります。JavaScriptには対応エンコーディングの一覧を取得するAPIはありませんが、TextDecoder を使えば個別に「使えるかどうか」をチェックできます。
new TextDecoder(エンコーディング名) を try/catch で囲み、RangeError が出なければサポートされていると判定します。UTF-8・Shift_JIS・EUC-JP などWHATWG Encoding Standard に載っているラベルはすべて対応しており、対応外の無効なラベルのときだけ例外になります。TextDecoder で判定する(基本)
TextDecoder はサポートしていないエンコーディング名を渡すと RangeError を投げる仕様です。これを try/catch で捕まえれば、サポートの有無を真偽値で返せます。
function isEncodingSupported(encoding) {
try {
new TextDecoder(encoding);
return true;
} catch (e) {
// 未対応のラベルだと RangeError になる
return false;
}
}
console.log(isEncodingSupported("UTF-8")); // true
console.log(isEncodingSupported("Shift_JIS")); // true
console.log(isEncodingSupported("EUC-JP")); // true
console.log(isEncodingSupported("Big5")); // true
console.log(isEncodingSupported("foo-123")); // false(無効なラベル)
EUC-JP は WHATWG Encoding Standard の正式なラベルで、モダンブラウザ・Node.js の TextDecoder はすべて対応しています。false になるのは "foo-123" のような規格に存在しないラベルだけです。ラベルは別名・大文字小文字を区別しない
エンコーディング名(ラベル)は大文字小文字を区別せず、複数の別名(エイリアス)が認められています。判定後に TextDecoder の encoding プロパティを見ると、正規化された名前が分かります。
console.log(isEncodingSupported("sjis")); // true(Shift_JIS の別名)
console.log(isEncodingSupported("shift-jis")); // true
// 正規化された名前を確認
console.log(new TextDecoder("sjis").encoding); // "shift_jis"
console.log(new TextDecoder("UTF-8").encoding); // "utf-8"
注意:TextEncoder は UTF-8 専用
混同しやすいのですが、エンコード側の TextEncoder は UTF-8 しか扱えません。引数にエンコーディングを渡しても無視され、常に UTF-8 になります。つまり「Shift_JIS でエンコードする」標準APIは存在しません(デコード=TextDecoder だけが多言語対応)。
const enc = new TextEncoder("shift_jis");
console.log(enc.encoding); // "utf-8"(shift_jis は無視される)
console.log(new TextEncoder().encoding); // "utf-8"
TextDecoder)側です。Shift_JIS や EUC-JP のバイト列を読み込んで文字列に変換する用途で使います。実用例:Shift_JIS ファイルを読み込む
判定の典型的な使いどころが、Shift_JIS など非UTF-8のファイル読み込みです。FileReader の readAsArrayBuffer() でバイト列を取得し、サポートを確認したうえで TextDecoder でデコードします。
function readShiftJIS(file) {
const encoding = "shift_jis";
if (!isEncodingSupported(encoding)) {
throw new Error(encoding + " は未対応です");
}
const reader = new FileReader();
reader.onload = () => {
const bytes = new Uint8Array(reader.result);
const text = new TextDecoder(encoding).decode(bytes);
console.log(text); // UTF-16 文字列としてそのまま扱える
};
reader.readAsArrayBuffer(file);
}
// Shift_JIS の「あ」は 0x82 0xA0
const bytes = new Uint8Array([0x82, 0xA0]);
const text = new TextDecoder("shift_jis").decode(bytes);
console.log(text); // "あ"
不正なバイトを検出する(fatal オプション)
「ラベルが対応しているか」とは別に、実際のバイト列がそのエンコーディングとして正しいかを厳密にチェックしたいこともあります。{ fatal: true } を付けると、不正なバイトで例外を投げるため、エンコーディング推定の判定材料に使えます。
const bytes = new Uint8Array([0xff, 0xfe, 0x00]);
// 既定(非fatal)は置換文字に置き換えてエラーにしない
console.log(new TextDecoder("utf-8").decode(bytes)); // 文字化け(置換文字)
// fatal:true は不正バイトで例外を投げる
try {
new TextDecoder("utf-8", { fatal: true }).decode(bytes);
} catch (e) {
console.log(e.name); // "TypeError"
}
まとめて確認:判定のポイント
| やりたいこと | 書き方 |
|---|---|
| ラベルが対応しているか | try { new TextDecoder(label) } catch { ... } |
| 正規化された名前 | new TextDecoder(label).encoding |
| バイト列が正しいか | new TextDecoder(label, { fatal: true }) |
| エンコード(出力) | new TextEncoder()(UTF-8固定) |
よくある質問(FAQ)
new TextDecoder(エンコーディング名) を try/catch で囲み、RangeError が発生しなければサポートされていると判定します。UTF-8・Shift_JIS・EUC-JP などWHATWG Encoding Standard のラベルはすべて対応しています。isEncodingSupported() で1つずつ判定する形になります。対応ラベルの定義は WHATWG Encoding Standard を参照してください。TextEncoder はUTF-8専用で、new TextEncoder("shift_jis") としても引数は無視されUTF-8になります。Shift_JIS で書き出すには外部ライブラリ(encoding.js など)が必要です。なお読み込み(デコード)は TextDecoder("shift_jis") で可能です。"UTF-8" も "utf-8" も、"Shift_JIS" も "sjis" も同じものとして扱われます。正規化後の名前は new TextDecoder(label).encoding で確認できます。まとめ
JavaScriptでエンコーディングのサポート有無を判定する方法のポイントを整理します。
- 基本は
new TextDecoder(label)をtry/catch(RangeErrorで未対応) UTF-8・Shift_JIS・EUC-JPもすべて対応(true)- ラベルは大文字小文字・別名を区別しない。
.encodingで正規化名を確認 TextEncoderはUTF-8専用(エンコードは多言語非対応)- バイト列の妥当性は
{ fatal: true }で検出できる
関連として、日本語をBase64形式にエンコード・デコードする方法・文字コードを取得・変換する方法・文字コードを判別する方法もあわせて確認すると、文字コードの扱いに強くなれます。
