7

Rubyを使用してファイルのURLを抽出し、ダウンロードしてダウンロードしています。ファイル名には utf8 文字が含まれています。例:

www.domain.com/.../ÖÇÄÜ360ÓïÒôÖúÀí.txt

上記の URL をダウンロードしようとすると、失敗します。を使用URI::escapeしても機能しない URI が生成されます。

www.domain.com/.../%C3%96%C3%87%C3%84%C3%9C360%C3%93%C3%AF%C3%92%C3%B4%C3%96%C3%BA%C3%80%C3%AD.txt

しかし、 URL Encoding Referenceに従えば、うまくいきます:

www.domain.com/.../%D6%C7%C4%DC360%D3%EF%D2%F4%D6%FA%C0%ED.txt

Ruby でまったく同じエンコーディングを行う関数を検索しようとしましたが、見つかりませんでした。上記のリンクの表を実装する関数を作成する前に、これを行う既存のライブラリを知っている人がいるかどうかを尋ねたいと思います。そして、これを行うことにした場合、明らかにすべてではなく、どの範囲の文字をエンコードする必要がありますか。

RUBY_VERSION => "1.8.7" で JRuby 1.6.2 を使用しています

4

1 に答える 1

15

ああ、文字エンコードの喜び!

ここで起こっていることは次のとおりです。Rubyは、抽出した文字列を、ファイル名のutf-8エンコーディングであるバイトシーケンスとして内部的に保存しています。これを呼び出すURI.escapeと、それらのバイトは%xyフォーマットでエスケープされ、結果の文字列は現在ASCII範囲のバイトのみで構成されており、URLとして使用されます。

ただし、受信サーバーは、これらのバイトを(%xyフォームからエスケープ解除した後)別のエンコーディング(この場合はISO-8859-1 )であるかのように解釈しているため、結果として得られるファイル名は、それが持っているものと一致しません。 。

これは、Ruby 1.9を使用したデモンストレーションです。これは、エンコーディングのサポートが優れているためです。

1.9.3-p194 :003 > f
 => "ÖÇÄÜ360ÓïÒôÖúÀí.txt" 
1.9.3-p194 :004 > f.encoding
 => #<Encoding:UTF-8> 
1.9.3-p194 :005 > URI.escape f
 => "%C3%96%C3%87%C3%84%C3%9C360%C3%93%C3%AF%C3%92%C3%B4%C3%96%C3%BA%C3%80%C3%AD.txt" 
1.9.3-p194 :006 > g = f.encode 'iso-8859-1'
 => "\xD6\xC7\xC4\xDC360\xD3\xEF\xD2\xF4\xD6\xFA\xC0\xED.txt" 
1.9.3-p194 :007 > g.encoding
 => #<Encoding:ISO-8859-1> 
1.9.3-p194 :008 > URI.escape g
 => "%D6%C7%C4%DC360%D3%EF%D2%F4%D6%FA%C0%ED.txt"

したがって、この場合の解決策は、文字列をエスケープする前にISO-8859-1としてエンコードすることです。Ruby 1.9では、上記のようにこれを行います。以前のバージョンでは、Iconvを使用できます(JRubyにはIconvが含まれていると思いますが、実際にはJRubyにあまり詳しくありません)。

1.8.7 :001 > f
 => "\303\226\303\207\303\204\303\234360\303\223\303\257\303\222\303\264\303\226\303\272\303\200\303\255.txt" 
1.8.7 :005 > g = Iconv.conv('iso-8859-1', 'utf-8', f)
 => "\326\307\304\334360\323\357\322\364\326\372\300\355.txt" 
1.8.7 :006 > URI.escape f
 => "%C3%96%C3%87%C3%84%C3%9C360%C3%93%C3%AF%C3%92%C3%B4%C3%96%C3%BA%C3%80%C3%AD.txt" 
1.8.7 :007 > URI.escape g
 => "%D6%C7%C4%DC360%D3%EF%D2%F4%D6%FA%C0%ED.txt" 

一般に、特定のエンコーディングを使用しているサーバーに依存することはできないことに注意してください。utf-8を使用する必要がありますが、この場合は明らかにそうではありません。

于 2012-05-10T22:42:12.950 に答える