rubyでURLエンコード
ちなみに HTML Encode の方法はこちらから。
でも、調べてみるとどうもいろいろなややこしいことが発覚して、ブルーなハワイ気分になりました。
結論からいうと、
require 'cgi'
CGI.escape('URLエンコードしたい文字')
なのです。
文字コードにより URL エンコード結果も変わってきますから、その場合は、
require 'cgi'
CGI.escape('URLエンコードしたい文字'.toutf8)
CGI.escape('URLエンコードしたい文字'.tosjis)
CGI.escape('URLエンコードしたい文字'.toeuc)
などと適宜変えてみてください。
それで、なにがややこしかったか、というと、最初は、
require 'uri'
p URI.escape('http://www.example.com/hyonyarara/?abc=まりも&def=阿寒湖')
の結果が
http://www.example.com/hyonyarara/?abc=%E3%81%BE%E3%82%8A%E3%82%82&def=%E9%98%BF%E5%AF%92%E6%B9%96
となって、楽でイイー、と思っていたのですが、パラメータの値に & (アンパーサンド)を入れたい!と思ったときに不都合が発生いたしましたのよ!
上記の例でいうと、「まりも」の「まり」と「も」の間に & を入れた値を渡したいと言うときに、
require 'uri'
p URI.escape('http://www.example.com/hyonyarara/?abc=まり&も&def=阿寒湖')
の結果は
http://www.example.com/hyonyarara/?abc=%E3%81%BE%E3%82%8A&%E3%82%82&def=%E9%98%BF%E5%AF%92%E6%B9%96
となりまして、ダメェなのですよ。
下のような結果だったらいいのにな。
http://www.example.com/hyonyarara/?abc=%E3%81%BE%E3%82%8A%26%E3%82%82&def=%E9%98%BF%E5%AF%92%E6%B9%96
という訳で、URI.escape は、私としてはツカエナイ関数になっています。いけすぅ。
それで、前述の CGI.escape の登場です。上記の URL をエンコードしたい場合、どうするかというと、
require 'cgi'
p 'http://www.example.com/hyonyarara/?abc=' + CGI.escape('まり&も') + '&def=' + CGI.escape('阿寒湖')
になるわけでした。
[追記 07/07/23]
いやいやでも rails だとクラシックスタイルの ?abc=まりも&def=阿寒湖 みたいな書き方はあまりしないですね。
map.connect ':controller/:action/:id'
↑のようなマッピングに対するURIの場合は URI.escape を使っても支障がないように思います。
[追記 07/08/01]
さらに URI.encode に追い風が。
URI.encode が CGI.encode の代わりになりますよ、という投稿をいただきました。
詳しくはcomments欄を見てみてくださいな。
【広告】
COMMENT
URI.escapeはURI全体にかぎらず、パラメータ単体に適用してもいいと思います。(あるいは、これは誤用なのでしょうか?)
その際、上述のようにALNUMを危険文字に指定してやれば、パラメータ自体がアンパサンド(&/&)を含む場合に対応できます。
ちょっと私ど素人も、ヒデトックスさんのコメントをきっかけに更に調べてみましたこと3時間。
その結果、半角スペースのエンコード問題というのが持ち上がりました。
URI.escape( ' ', Regexp.new("[^#{URI::PATTERN::ALNUM}]") )
は、%20
CGI.escape( ' ' )
は、+
にそれぞれ変換されました。
そして、ruby を cgi (apache2.0) として使った場合や、rails で動かしている場合で、form から get メソッド(method)で送信すると、スペースは + として変換されました。
さらに、デコードについても調べてみました。
%20 や + をデコードするとどうなるのでしょうか。
URI.unescape( '%20' )
は、スペース
URI.unescape( '+' )
は、+
CGI.unescape( '%20' )
は、スペース
CGI.unescape( '+' )
は、スペース
という結果になりました。
ちなみに、+ や %20 を rails に get パラメータとして渡してみたら、どちらも半角スペースに勝手にデコードされていました。
まとめますと、GET パラメータの値をエンコードするときは、
URI.escape( str, Regexp.new("[^#{URI::PATTERN::ALNUM}]") )
CGI.escape( str )
のどちらでも良いけども、何かの機会で上記の escape を unescape しなければならない場合、CGI.escape の文字は、必ず CGI.unescape を使うこと。
間違って CGI.escape の文字に URI.unescape を使うと、escape 前にスペースだった文字が、unescape に + になっちゃうよ、ということですね。
でもどっちかっていうと、cgi や rails の動きに合わせて、CGI.escape を使っておいた方が無難そうな予感です。
で、合ってるのかなぁ?ほかにも留意点がありそうですね。
rfc 規格の神様オタスケを~
仕事ではWin系(C#)やってるんですけど、飽きていて
家でUbuntu-Rubyをいじっているものです。
まだ初心者ですけど、また見せてもらって、コメント
とかさせてもらいたいとおもっています。よかったら、
私のブログもみてやってください。
'&'と'%29'の件ですけど、Rubyの正規表現とかの
話は関係ないでしょうか。たしかRubyって
シングルクォートは単純な文字列('n'=n)
ダブルクォートは正規表現("n"=改行)を使える
と思っていますが、その辺が何か役にたたないでしょうか?立たなかったら、ゴメンなさい^^。
では、よろしくお願いします^^。
言語って後から後からGoやらF#やらいろいろ出てきますので自分のフィーリングに合うものと親密にお付き合いするんじゃないと私の脳ではつぶれてしまいそうですよ!
とはいえホリエモンも言ってましたけど、Cを知っている人がJavaを使えるようになるにはそうそう苦労はいらない、というように、一つの言語を覚えれば、他の言語を覚えるのもそうそうハードルが高いわけじゃあないと確かに思います。
むしろ、デザインパターンだったりアルゴリズムだったりに目が向いていく場合も多いと思います。
URI.escape(str[, unsafe])
URI.encode(str[, unsafe])
URI 文字列をエンコードした文字列を返します。unsafe には、URI として指定できない文字を正規表現か文字列で指定します(デフォルトは、定数 URI::UNSAFE
とありました。次のようにして使っています。
(WikipediaやAmazonのようにalpha,numberだけ残して残りをescapeしたい)
URI.escape( str, Regexp.new("[^#{URI::PATTERN::ALNUM}]") )