2009年01月17日 20:30 [Edit]

このエントリーをはてなブックマークに追加
javascript - URI Encode と Punycode の共存

デモ

以下のフィールドで相互変換できるようになっています。

全部encodeURIComponent()してしまう版と、「日本語URL変換ツール 〜 ピュニコード(Punycode)・UTF-8などのエンコードに」のように「URIのASCII化」だけする版と両方あります。

Decoded:
Encoded:
Ascii-fied:

テスト用のリンク

ソース

Punycode変換のコードを書いてみました - Operaの備忘録のぺえじ - チーム俺等」のpunycode.jsを使わせていただきました。おかげでかなりシンプルです。

で、punycode.jsにマイナーバグを見つけたのでご報告。英数字だけの文字列を入れると、尻に余計な-が付きます。本entryのscriptへの影響はありません。punycode化が不要な場合はすっとばすようになっているので。

var re_fullstop = new RegExp(
    '[\u002E\u0589\u06D4\u0701\u0702\u1362\u166E\u1803'
  + '\u1809\u2CF9\u2CFE\u3002\uFE12\uFE52\uFF0E\uFF61]'
);

decodeIDN = function(str){
    return str.replace(/xn--([0-9a-z\-]+)/g, function(m0, m1){
        return Punycode.decode(m1);
    });
};

encodeIDN = function(str){
    var words = str.toLowerCase().split(re_fullstop);
    for (var i = 0, l = words.length; i < l; i++){
        if (! words[i].match(/[^0-9a-z\-]/)) continue;
        words[i] = 'xn--' + Punycode.encode(words[i]);
    }
    return words.join('.');
};

decodeURIComponentIDN = function(uri){
    return decodeURIComponent(uri).replace(/\:\/\/([^\/]+)/, function(m0,m1){
        return '://' + decodeIDN(m1);
    });

};

encodeURIComponentIDN = function(str){
    return encodeURIComponent(str.replace(/\:\/\/([^\/]+)/, function(m0,m1){
        return '://' + encodeIDN(m1);
    }));
};

unicodeToURI = function(str){
    return str.replace(/\:\/\/([^\/]+)/, function(m0,m1){
        return '://' + encodeIDN(m1);
    }).replace(/[^A-Za-z0-9_\;\/\?\:\@\&\=\+\$\,\[\]\-_\.\!\~\*\(\)]+/g,
        function(m0){
            return encodeURIComponent(m0);
    });
};

Enjoy!

Dan the Man with too Many Encodings to Support


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

この記事へのコメント
末尾に"-"が付く仕様は、RFC 3492 に掲載されているサンプルコードに倣ったものです。また、私見でもエンコード/デコードの双方向性を確保するために末尾の"-"は必要かなぁ、と思います。

よって、「どんなホスト名でもとりあえず変換しとけ」というわけには行かなくなりますけど、その辺りの判定は punycode.js の領分ではないと考えています(今のところは)。
Posted by misttrap at 2009年01月18日 02:21