Unicodeエスケープ
付箋紙Greasemonkeyで、GM_setValueに登録した日本語の文字化け対策にencodeURIをつかったけど、encodeURIはURIをエンコードするための関数なのであんまり褒められた使い方ではないですね。しかも、encodeURIのようなURLエンコーディングは文字列をUTF-8にしてから、エンコード対象の各バイトを%xx形式*1で表現するので、日本語1文字をあらわすのにたいていの場合ASCII9文字が必要になって効率が悪いです。*2
なので、前述のような単に非ASCII文字をエスケープしたいだけのようなケースではUnicodeエスケープを使った方がよいです。Javaのpropertiesとかnative2asciiとかのやつです。
Unicodeエスケープは\uxxxx*3の形式であらわすので、たいていの日本語1文字はASCII6文字になって、URLエンコーディングに比べて3分の2ぐらいに圧縮できます。印字可能なASCII記号と半角スペースもエスケープしないのでその分も短くなるし。
JavaScriptにはUnicodeエスケープをするための標準関数は備わっていないけど*4、Stringのコールバック関数つきreplaceメソッドを使えば、以下のように簡単に作れます。
function escapeUnicode(str) { return str.replace(/[^ -~]|\\/g, function(m0) { var code = m0.charCodeAt(0); return '\\u' + ((code < 0x10)? '000' : (code < 0x100)? '00' : (code < 0x1000)? '0' : '') + code.toString(16); }); } function unescapeUnicode(str) { return str.replace(/\\u([a-fA-F0-9]{4})/g, function(m0, m1) { return String.fromCharCode(parseInt(m1, 16)); }); }
replace関数について補足
repalceの第一引数が正規表現、第二引数が置換文字列またはコールバック関数です。コールバック関数を指定した場合は、正規表現がマッチするたびに関数が呼び出されます。ただし、正規表現に gオプションをつけていない場合は、最初のマッチ箇所しか置換されません。
コールバック関数には、正規表現内のグループ数をNとして、N+3個の引数が渡されます。functionに明示的に引数リストを定義して受け取っても、argumentsオブジェクトからアクセスしてもOKです。引数リストを定義する場合も、上のescapseUnicode関数でのように必要な分だけを定義すればよいです。
それぞれの引数の内容は以下の通りです。
arguments | 内容 |
---|---|
arguments[0] | マッチした箇所の文字列 |
arguments[1]〜arguments[N] | 正規表現のグループ参照 |
arguments[N+1] | マッチした箇所のインデックス |
arguments[N+2] | replace関数を呼び出した文字列 |
*1:xxは16進数2桁
*2:ちなみに、encodeURIとよく似たencodeURIComponentという関数もある。違いはURI内で意味を持つ記号[/:?&;#]をエスケープするかしないか。encodeURIはそれらをエスケープしない。なのでGETパラメータに指定する文字列はencodeURIComponentを使ってエンコードする必要がある。逆にどんな場合にencodeURIを使うとよいのかはよくわからない (^^;
*3:xxxxは16進数4桁
*4:Unicodeエスケープと(実装によっては)よく似たエスケープをするescape/unescape関数がJavascriptには標準でありますが、ブラウザ間の互換性などいろいろ微妙なので今はあまり使われていません。