2012-05-10 30 views
7

Tôi đang sử dụng Ruby để trích xuất URL của tệp để tải xuống và tải xuống. Tên tệp có utf8 ký tự, ví dụ:Tôi làm cách nào để mã hóa URL của các ký tự ASCII?

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

Khi cố gắng tải xuống URL ở trên, không thành công. Sử dụng URI::escape tạo ra một URI mà cũng không làm việc:

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 

Nhưng nếu tôi làm theo các URL Encoding Reference, nó hoạt động:

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

tôi đã cố gắng để tìm kiếm một chức năng trong Ruby mà không được chính xác cùng mã hóa, nhưng tôi không thể tìm thấy bất kỳ mã nào. Trước khi tôi cố gắng viết một hàm thực hiện bảng trong liên kết ở trên, tôi muốn hỏi xem có ai biết bất kỳ thư viện hiện có nào thực hiện điều này không. Và nếu tôi quyết định làm điều này, những ký tự nào tôi nên mã hóa, rõ ràng, không phải mọi thứ.

Tôi đang sử dụng JRuby 1.6.2 với RUBY_VERSION => "1.8.7"

+1

Các byte C3 96 là mã UTF-8 Ö. Cùng một ký tự được biểu diễn bằng ASCII dưới dạng byte đơn D6. Vì vậy, một cách để tiếp cận vấn đề là chuyển đổi các ký tự UTF-8 thành ASCII, nơi bạn có thể, và sau đó là URI :: escape. Nhưng điều đó sẽ không giúp bạn đối với các ký tự Unicode không tương đương ASCII. –

+0

Bạn đã thử ['CGI.escape'] (http://ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI.html#method-c-escape) chưa? –

+0

@DavidGorsline: Tính năng này không hoạt động. Tôi kết thúc với '?' cho tất cả các ký tự ngoại trừ '360' và '.txt'. Ví dụ trên là một ví dụ thực tế, hãy làm gì nếu bạn có bất kỳ ý tưởng nào bạn có thể kiểm tra chúng trên chuỗi'ÖÇÄÜ360ÓïÒôÖúÀí.txt 'và cho tôi biết cách thực hiện. Cảm ơn rất nhiều vì đã giúp bạn. – Rami

Trả lời

15

Ồ, niềm vui của mã hóa ký tự!

Điều gì đang xảy ra ở đây là như sau. Ruby trong nội bộ lưu trữ chuỗi bạn đã trích xuất dưới dạng chuỗi byte là mã hóa utf-8 của tên tệp. Khi bạn gọi URI.escape trên đó, các byte đó được thoát ở định dạng %xy và chuỗi kết quả, hiện chỉ bao gồm các byte trong phạm vi ASCII, được sử dụng làm url. Tuy nhiên, máy chủ nhận sẽ giải thích các byte đó (sau khi không định dạng chúng từ %xy biểu mẫu) như thể chúng ở dạng mã hóa khác, trong trường hợp này là ISO-8859-1 và do đó tên tệp kết quả mà nó xuất hiện không khớp với bất kỳ thứ gì có.

Đây là bản trình diễn sử dụng Ruby 1.9, vì nó có hỗ trợ tốt hơn cho mã hóa. do đó

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" 

Giải pháp trong trường hợp này là để mã hóa các chuỗi như ISO-8859-1 trước khi thoát nó. Trong Ruby 1.9 bạn làm điều này như trên, trong các phiên bản trước đó bạn có thể sử dụng iconv (tôi giả sử JRuby bao gồm iconv, tôi thực sự không phải là quen thuộc với 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" 

Lưu ý rằng nói chung bạn có thể' t phụ thuộc vào máy chủ bằng cách sử dụng bất kỳ mã hóa cụ thể nào. Nó nên đang sử dụng utf-8, nhưng rõ ràng là không phải trong trường hợp này.

+0

Tuyệt vời, cảm ơn! – Rami

+0

Điều này rất hữu ích không có một đầu mối mà tôi cần đến URI.escape sau khi mã hóa. – KnuturO