SOFTELメモ Developer's blog

会社概要 ブログ 調査依頼 採用情報 ...
技術者募集中

【JavaScript】window.btoa(‘日本語’) する

問題

JavaScriptでbase64エンコード、デコードをするなら、window.btoa, window.atob がありますよね。

window.btoa('Hello!'); // → "SGVsbG8h"
window.atob('SGVsbG8h'); // → "Hello!"

日本語入れたらエラーになるんですけど、だめなんですか。

window.btoa('あいうえお'); // → x
// Error: String contains an invalid character

javascript-btoa

答え

殆どのブラウザでは、window.btoa のパラメータにユニコードの文字列を指定して呼び出すと、例外「範囲外 (Out Of Range)」が返ります。

https://developer.mozilla.org/ja/docs/Web/API/window.btoa#Unicode_Strings

window.btoa(‘日本語’) は通常無理だよとのこと。ついでに、btoa(“\u65e5\u672c\u8a9e”)もだめ

ただ、これなら期待した動作をする。

window.btoa(unescape(encodeURIComponent('日本語'))); // → "5pel5pys6Kqe"
decodeURIComponent(escape(window.atob('5pel5pys6Kqe'))); // → "日本語"

とりあえず期待した動作ができた。

なんでこれでいいの?

上の引用元ページ(MDN)にも掲載されている解決方法だが、「これで正しい」とは書いていない。

今のところはこれでうまくいっちゃうよ ということなのだが、詳細は以下のようになる。


encodeURIComponent

encodeURIComponentは最新のECMAScriptの仕様に定義があり、UTF-8でのURI用の%エンコードをする。

encodeURIComponentにUnicodeのU+3042(= “\u3042” = あ)をエンコードしてもらうと、こうなる。

encodeURIComponent('\u3042'); // → "%E3%81%82"
encodeURIComponent('あ'); // → "%E3%81%82"

たしかにUTF-8の”あ”の16進表現は 0xE3 0x81 0x82 (e38182) である(参考)。

ECMAScriptの定義があいまいで、encodeURIComponentは「特定の文字を」置き換えるそうだが、非ASCII文字がエンコードされる様子である。

unescape

一方、escape/unescape関数だが、最新のECMAScriptの仕様には定義がない。非推奨で、仕様からはずされ、実装は必須ではないとある。とはいえ、現段階でescape/unescape関数が即座に廃止されるのは考えにくい。

unescape関数は、パーセントエンコーディングされた文字列をアンエスケープする。一般的なパーセントエンコーディング(%XX)のみでなく、ユニコードパーセントエンコーディング(%uXXXX)も処理する。

>>> var e = encodeURIComponent('\u3042'); console.log(e);
%E3%81%82
>>> var u = unescape(e); console.log(u);
"ã" ← テキストとして見えないけど3文字ある

上の変数uに代入された文字列は、ASCIIのE3、81、82の文字である。

>>> u.charCodeAt(0).toString(16);
"e3"
>>> u.charCodeAt(1).toString(16);
"81"
>>> u.charCodeAt(2).toString(16);
"82"

unescapeするのは、decodeURIComponentするのとだいぶ違う。decodeURIComponentは渡された文字列をUTF-8として扱う。3つのエンコードされた文字はまた元のUTF-8の1文字に戻される。unescapeは単純にひとつずつ文字として返す。

こうして、unescape(encodeURIComponent())された文字列は、元のUTF-8の文字列の各バイトのASCII表現となる。

まとめ

以下のように変換されて、window.btoaに渡しても大丈夫な形になっていたのでした。

window-btoa

参考

http://ecmanaut.blogspot.jp/2006/07/encoding-decoding-utf8-in-javascript.html

http://monsur.hossa.in/2012/07/20/utf-8-in-javascript.html

関連するメモ

コメント