青山です。

On Sun, 2 Apr 2000 06:14:31 +0900,
Tomoyuki Kosimizu <greentea / fa2.so-net.ne.jp> wrote:

> def escape(string, unsafe=nil)
>   ## raise ArgumentError unless unsafe.nil? or unsafe.is_a? String
>   if not unsafe
>     string.gsub(/[^;\/?:@&=+$,A-Za-z0-9\-_.!~*'()\[\]]/n) do |match|
>       sprintf("%%%02X", match.unpack("C")[0])
>     end
>   else
>     string.gsub(/[#{unsafe}]/n) do |match|
>       sprintf("%%%02X", match.unpack("C")[0])
>     end
>   end
> end

URI::escape() はこれで良さそうですね。unsafe は String よりも Regexp
の方が良いような感じもしますが。

ところが一方 CGI に関しては、なひさんのご指摘どおり、
name1=value1&name2=value2 のような &= で切り分ける文字列になりますから、
name, value 部にはこれらが入ってはなりません。

考えてみれば、当り前ですよね。つまり、URI::escape() とはむしろ逆に、
reserved をエスケープしなければならない、と。

で、再度見直してみると、

RFC1866 section 8.2.1
>        1. The form field names and values are escaped: space
>        characters are replaced by `+', and then reserved characters
>        are escaped as per [URL]; that is, non-alphanumeric
>        characters are replaced by `%HH', a percent sign and two
>        hexadecimal digits representing the ASCII code of the
>        character.

これは実は読んだままで、アルファベット以外はすべてエスケープという事の
ようですね。Netscape, Lynx で確認してみると、' ' --> '+' は行っていて、
'_', '.', '-' はそのままのようですから、こんな感じになりそうです。

def CGI::escape(string)
  string.gsub(/ /n, '+').gsub(/([^a-zA-Z0-9_.-])/n) do
    sprintf("%%%02X", $1.unpack("C")[0])
  end
end

という事で、URI として正しい文字列を生成する為のエスケープと、URI に埋
め込んでデータを引き渡す CGI のエスケープはまったく別物であり、独立し
て存在する必要がある。また、利用者はそれらを適切に使い分ける必要がある。
となりそうです。

さて、遅くなってしまいましたが、1.4.4 に間に合うでしょうかね。


-- 
青山 和光 Wakou Aoyama <wakou / fsinet.or.jp>