%u符号化

escape(), unescape() (JavaScript)

[1] JavaScript関数 escape(), unescape() は、文字列パーセント符号化%u 符号化します。

[2] URL で用いられているパーセント符号化とは互換性がなく、 URL 用としては encodeURIComponent(), decodeURIComponent() などが用意されています。

仕様書

%u 符号化

[16] %uHHHH は、 JavaScript関数 escape(), unescape() で用いられている符号化です。 URLパーセント符号化と半ば意図的に混同され、現在でもたまに用いられています。

[17] 仕様上は URL%u 符号化を用いることは認められていません。

[4] Latin1 文字 (U+00FF 以下) は百分率符号化されます。

[5] それ以外の文字UTF-16 符号単位ごとに %u を使って符号化されます。

[6] 歴史的には、JavaScript エンジン内部コード (シフトJISUTF-16LE + BOM など) のまま百分率符号化されることがありました。

[7] 歴史的には、 U+0020+ になることがありました。

歴史

JavaScript

[18] %u による符号化ECMA-262 の第1版で escape(), unescape()関数の挙動として規定されました。 この挙動は紆余曲折を経て現在では各 JavaScript エンジンで実装されています。

[9] Escape ( 版) <http://web.archive.org/web/20050222015746/http://www.felix.jp/~yugo/js/guide/escape.html>

ECMA TC39 が ECMA-262 を制定するとき、escape および unescape は Unicode を用いると決めた。具体的には、Unicode エンコーディングが 0xFF 以下の文字は、16進法の数字二つの %HH 形式を用いる。 0xFF より大きい場合には、%uHHHH 形式を用いる。

MSIE のバージョン 4以降が用いる JScript では escape/unescape による URL エスケープが出来なくなった。

Netscape は、ECMA-262 に従わず、従来の ISO Latin-1 を使うと決定したため、Netscape Communicator 4.06 以降で用いられている JavaScript 1.3 でも escape/unescape を URL エスケープに利用できる。そのため、%uHHHH 形式はサポートされていない。

当初の実装では Mozilla でも ECMA-262 準拠で RFC 1738 非準拠の escape/unescape を使っていた。ところが、バグ報告があったため、2000年1月に従来通りの ISO Latin-1 を使った escape/unescape に変更された。

String Class を実装している js/src/jsstr.c で escape/unescape を実装している。 String Class を実装しているファイルに記述しているが、もちろん escape と unescape は Global オブジェクトのプロパティーである。実は、DOM の Window オブジェクトを実装している dom/src/base/nsJSWindow.cpp でも escape/unescape を実装している。こちらは従来通り ISO Latin-1 を使っている。 Mozilla は内部コードとして UCS-2 を用いており、読み込んだページは内部コードに変換されるが、DOM の escape/unescape は元のページの文字コードでエンコード/デコードする。

Mozilla では起動時に、SpiderMonkey の escape/unescape をいったん定義するが、その後 DOM の escape/unescape で上書きする。このため、Mozilla 上で escape/unescape を使うと ISO Latin-1 を用いた escape/unescape が呼び出され、SpiderMonkey を単体で動かした場合には ECMA-262 準拠の escape/unescape が呼ばれる。 Mozilla からは Unicode エスケープである ECMA-262 準拠の escape/unescape は利用できない。

もともと escape/unescape は JavaScript engine ではなく、Client-side 部分である libmocha で実装していたが、ECMA-262 が escape/unescape の仕様を定めたので、1998年5月に JavaScript engine で実装するように変更された。また、ECMA-262 になってスペースと "/" の扱いも変更された。「昔の libmocha の escape をエミュレートしたいのなら、第2引数で escape の振る舞いを指定しろ」というコメントが /js/src/jsstr.c に書いてある。このコメントの通り、第2引数に Bit 0, 1, 2 からなる mask を指定でき、この値に応じてスペースと "/" に対する振る舞いが変更される。 mask の値が不適切だと、"invalid string escape mask" というエラーが発生することがあるので注意すること。デフォルトが ECMA-262 の escape に対応した 7 である。ちなみに Java による JavaScript engine Rhino でも、mask 指定に対応している。

その escape/unescape だが、1999年12月に出た ECMA-262 3rd Edition では Compatibility の項に移されて、正式な仕様の一部ではなくなった。もっとも動作自体は 2nd Edition から変更されていない。

[10] Bug 22594 – [dogfood] JavaScript escape() is incompatable w/ 4.x ( 版) <https://bugzilla.mozilla.org/show_bug.cgi?id=22594>

[150] Bug 44272 - javascript escape and unescape don't work properly with unicode chars <https://bugzilla.mozilla.org/show_bug.cgi?id=44272>

Perl

[25] CGI.pm%HHHH復号を実装しています (非 EBCDIC 環境のみ)。 ただしサロゲート・ペアはそのまま2文字になってしまいます。

[26] URI::Escape::JavaScript - search.cpan.org <http://search.cpan.org/~taniguchi/URI-Escape-JavaScript-0.04/lib/URI/Escape/JavaScript.pm>

URI::Escape doesn't work for escaping and unescaping JavaScript like Unicode URI-escape ("%uXXXX"). But you can use this module to do those.

[27] 404 Blog Not Found:CPAN - URI::Escape::XS Released! ( 版) <http://blog.livedoor.jp/dankogai/archives/50818918.html>

もう一つは、%uHHHHの対応。一応にぽたん作のURI::Escape::JavaScriptというものがあるのですが、コードを見るとSurrogate Pairに未対応。

In spite of that, there are a significant number of URIs with %uHHHH escapes. Therefore this module supports decoding only.

IRI

[19] RFC 3987 - Internationalized Resource Identifiers (IRIs) ( 版) <http://tools.ietf.org/html/rfc3987#appendix-A.3>

Instead of using the existing percent-encoding convention of URIs, which is based on octets, the idea was to create a new encoding convention; for example, to use "%u" to introduce UCS code points. Using the existing octet-based percent-encoding mechanism does not need an upgrade of the URI syntax and does not need corresponding server upgrades.

[20] RFC 3987>>19 のように述べており、 %u を使う方法を導入せずとも既存のパーセント符号化だけで同じことが実現できて互換性も高いとしています。

[3] Functions - MDC Docs ( 版) <https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions>

The escape and unescape functions let you encode and decode strings. The escape function returns the hexadecimal encoding of an argument in the ISO Latin character set. The unescape function returns the ASCII string for the specified hexadecimal encoding value.

[14] JavaScriptにおけるURLエンコードの処理 ( ( 版)) <http://www.cresc.co.jp/tech/java/URLencoding/JavaScript_URLEncoding.htm>

[21] Percent-encoding - Wikipedia, the free encyclopedia ( 版) <http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations>

There exists a non-standard encoding for Unicode characters: %uxxxx, where xxxx is a Unicode value represented as four hexadecimal digits. This behavior is not specified by any RFC and has been rejected by the W3C. The third edition of ECMA-262 still includes an escape(string) function that uses this syntax, but also an encodeURI(uri) function that converts to UTF-8 and percent-encodes each octet.

[22] escape() を誤って使っているらしく %u が使われることが今でも大きなサイトでもあったりします。

[24] ニコニコ動画URL%u が使われています。

[23] 民泊のエアビーアンドビー、苦情サイト新設 - WSJ ( (NATHAN OLIVAREZ-GILES著, )) <http://jp.wsj.com/articles/SB10513819889225894892604582103810164964978>

<meta name="apple-itunes-app" content="app-id=364387007,app-argument=wsj://launch?articleid=SB10513819889225894892604582103810164964978&headline=%u6C11%u6CCA%u306E%u30A8%u30A2%u30D3%u30FC%u30A2%u30F3%u30C9%u30D3%u30FC%u3001%u82E6%u60C5%u30B5%u30A4%u30C8%u65B0%u8A2D&weburl=http://jp.wsj.com/articles/SB10513819889225894892604582103810164964978" />

<meta name="al:ios:url" content="wsj://launch?articleid=SB10513819889225894892604582103810164964978&headline=%u6C11%u6CCA%u306E%u30A8%u30A2%u30D3%u30FC%u30A2%u30F3%u30C9%u30D3%u30FC%u3001%u82E6%u60C5%u30B5%u30A4%u30C8%u65B0%u8A2D&weburl=http://jp.wsj.com/articles/SB10513819889225894892604582103810164964978" />