2007年03月10日 17:30 [Edit]

javascript - encodeURIUnicode()と%uXXXX問題

これを見て、(de|en)codeURIUnicodeがあればいいと思ったので作ってみた

sawatの日記 - Unicodeエスケープ
なので、前述のような単に非ASCII文字をエスケープしたいだけのようなケースではUnicodeエスケープを使った方がよいです。Javaのpropertiesとかnative2asciiとかのやつです。

Decoded:
Encoded:

要は、U+00ffまではencodeURIComponent互換、それ以上はescape()互換というもの。こうしてencodeされたものは、CGI.pmとかでもほぼそのまま使える。

ただし、この「ほぼ」という奴がくせ者で、現状JavaScriptでは、BMPより上の文字はJavaと同じくSurrogate Pairで表現する。例えば「𪚲」(U+2A6B2)は、実体参照では𪚲なのだが、"𪚲".lengthは2であり、escape表現だと%uD869%uDEB2となる。こうなるとCGI.pmでも食えなくなる。にぽたんがリリースしたURI::Escape::JavaScriptもSurrogate Pair問題が未解決だった。

こういう問題があるせいか、RFCにも

RFC 3986
pct-encoded = "%" HEXDIG HEXDIG

はあっても、

pct-u-encoded = "%u" HEXDIG HEXDIG HEXDIG HEXDIG

のようなものは見当たらない。現時点ではデータ交換用としては避けた方が吉のようだ。

Dan the Man with too Many Transcoders to Maintainer

Source Code:
var _noEscapeChars = {};
(function(str){
    for (var i = 0, l = str.length; i < l; i++){
        _noEscapeChars[str.charAt(i)] = 1;
    }
})(
    '0123456789'
  + 'abcdefghijklmnopqrstuvwxyz'
  + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  + '-_.!~*\'()'
);
function encodeURIUnicode(str){
    var result = '';
    for (var i = 0, l = str.length; i < l; i++){
        var c = str.charAt(i);
        if (_noEscapeChars[c]){
            result += c;
        }else{
            var ord = c.charCodeAt(c);
            var hex = ord.toString(16);
            if( ord < 256 ){
                if (hex.length < 2) hex = '0' + hex;
                result += '%' + hex.toUpperCase();
            }else{
                while (hex.length < 4){
                    hex = '0' + hex;
                }
                result += '%u' + hex.toUpperCase();
            }
        }
    }
    return result;
}
function decodeURIUnicode(str){
    var result = '';
    for (var i = 0, l = str.length; i < l; i++){
        var c = str.charAt(i);
        if (c == '%'){
            if (str.charAt(i+1) == 'u'){
                var hex = str.substr(i+2, 4);
                result += String.fromCharCode(parseInt(hex, 16));
                i += 5;
            }else{
                var hex = str.substr(i+1, 2);
                result += String.fromCharCode(parseInt(hex, 16));
                i += 2;
            }
        }else{
            result += c;
        }
    }
    return result;
}

この記事へのトラックバックURL

この記事へのトラックバック
そんなことは、ない。 JavaScriptには\uXXXXがあるんですよ[文系大学的IT系の悲哀] dankogaiさんはあまりJavaScriptのリテラルに詳しくないのかな? \uXXXXを使わないのは、訳がある。
javascript - \uXXXXを使わない理由【404 Blog Not Found】at 2008年01月14日 14:37
Perlに限らず、動的に名前空間を書き換えることができる言語ならコンセプトはパクれるはずのtips.
perl - パッチなしでパッチする【404 Blog Not Found】at 2007年04月09日 16:18