文字列と UTF-8 バイト列の相互変換
2006-10-23


やっていることは「高度な JavaScript 技集」の「UTF-8 <-> UTF16 変換」と同じ。

function toUTF8Octets(string) {
  return unescape(encodeURIComponent(string));
}

function fromUTF8Octets(octets) {
  return decodeURIComponent(escape(octets));
}

encodeURIComponentencodeURI でもいい (むしろそのほうが処理する文字種が減って速くなりそう) が、decodeURIComponentdecodeURI にすると一部の文字 ("?"、"#" など) がデコードされなくなる。

使いどころ

Base64 エンコードする関数 (「高度な JavaScript 技集」の base64encode や Firefox など Gecko 系ブラウザで実装されている btoa[LINK]) では渡された文字列をバイト列として扱う (btoa では \u0100 以上の文字を含む文字列を渡すとエラーになる)。なので、あらかじめ文字列をバイト列に変換しておく必要がある。

btoa(toUTF8Octets("Base64 エンコード"));
// QmFzZTY0IOOCqOODs+OCs+ODvOODiQ==

なお、data URI を扱う際に Base64 は必須ではない。英数字以外の文字が多く含まれている場合 (画像など) は Base64 エンコードしたほうが長さの点から有利だが、そうでなければ内容を URL エンコードするだけで十分だ。

location.href = "data:text/plain;charset=utf-8," + encodeURI("日本語も OK");

余談だが、C 言語の atoi が頭にあると、つい atob が文字列を Base64 エンコードするものと思ってしまうが (b = Base64 という連想)、実際はその逆だ。btoa は Binary to ASCII ということなのだろうか。

XUL アプリケーションでの使いどころ

通常、テキストファイルに書き込むときは nsIOutputStream::write[LINK] を使うが、これは文字列をバイト列として扱うので、日本語文字などをそのまま渡すと文字化けする。テキストファイルを読み込むときも、nsIScriptableInputStream::read[LINK] で返されるのはバイト列を表現する文字列である。

そのため、ファイル入出力の際に日本語文字などを扱うためには、Gecko 1.8 / Firefox 1.5 から導入された nsIConverterInputStream[LINK] / nsIConverterOutputStream[LINK]、または nsIScriptableUnicodeConverter[LINK] を使うのだが、いちいちほかの XPCOM コンポーネントを利用するまでもない・文字コードは UTF-8 決め打ちでいいというときは以下のようにできる。

// file に content を UTF-8 で書き込む
function writeTo(/* nsIFile */ file, /* String */ content) {
  var stream = Components.classes['@mozilla.org/network/file-output-stream;1']
                         .createInstance(Components.interfaces.nsIFileOutputStream);
  stream.init(file, 0x02 | 0x08 | 0x20, 420, -1);
  content = toUTF8Octets(content);
  stream.write(content, content.length);
  stream.close();
}

また、prefs.js から設定を読み書きする際も、nsIPrefBranch::setComplexValue[LINK] / getComplexValue[LINK]


続きを読む

[Mozilla Firefox]
[JavaScript]

コメント(全2件)
コメントをする


記事を書く
powered by ASAHIネット