TextDecoder
でバイト列を文字列に変換しようとしたら、意外な形で引っかかってしまいました。
TL; DR
-
TextDecoder
にlatin1
やascii
と指定しても、実際にはWindows-1252として処理される - latin1とWindows-1252では、0x80 - 0x9Fのマッピングが違う
- バイナリ文字列を配列に起こすなど、0x80 - 0x9FをU+0080 - U+009Fにそのまま対応させたい用途には使えない
TextDecoder
とは
TextDecoder
は、配列に入った数値の組を、文字コードとして解釈して文字列に変換するためのクラスです。対応するエンコードはUnicode系だけでなく豊富に用意されていて、たとえば日本語用のSJIS、EUC-JP、ISO-2022-JPも存在します(JavaScriptコードとしてテーブルを持たずに、これらのエンコードを解釈できる、ということになります)。
latin1
を使ってみたら
その中にlatin1
があったので、atob
の結果を投げ込んでバイト配列にしてみたのですが…おかしな値を出していることに気づいてしまいました。
調べてみた結果
先ほど挙げた エンコードリストのページを見たところ、latin1
、ascii
、us-ascii
などのように指定した場合、実際にはWindows-1252(Wikipedia)というエンコーディングが使われることが判明しました。この2つの違いは、
- latin1…0x80 - 0x9Fには制御コードが入っている(UnicodeでもU+0080 - U+009Fに同じ形で入っている)
- Windows-1252…0x80 - 0x9Fには一部を除いて文字が入っている(Unicodeと単純なマッピングにはならない)
というもので、latin1で書かれた普通の文書であれば0x80 - 0x9Fの文字がないので問題にはならないのですが、atob
の結果など256通りのバイトパターンが全て使われている場合には大問題となってしまいます。
結論
TextDecoder
で得られた結果のうち、マッピングが違う文字だけあとから置換する、というようなことを試してみたりもしたのですが、結局は素直にfor
でString.fromCharCode
を動かして文字列を継ぎ足す、という原始的な方法が最速だったのでそれでいいかなとなっています。