Cách URL mã hóa một chuỗi trong Ruby


135

Làm thế nào để tôi URI::encodemột chuỗi như:

\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a

để có được nó trong một định dạng như:

%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

theo RFC 1738?

Đây là những gì tôi đã thử:

irb(main):123:0> URI::encode "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
ArgumentError: invalid byte sequence in UTF-8
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:219:in `gsub'
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:219:in `escape'
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:505:in `escape'
    from (irb):123
    from /usr/local/bin/irb:12:in `<main>'

Cũng thế:

irb(main):126:0> CGI::escape "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
ArgumentError: invalid byte sequence in UTF-8
    from /usr/local/lib/ruby/1.9.1/cgi/util.rb:7:in `gsub'
    from /usr/local/lib/ruby/1.9.1/cgi/util.rb:7:in `escape'
    from (irb):126
    from /usr/local/bin/irb:12:in `<main>'

Tôi đã xem tất cả về internet và không tìm thấy cách nào để làm điều này, mặc dù tôi gần như tích cực rằng ngày khác tôi đã làm điều này mà không gặp rắc rối nào cả.


1
Có thể hữu ích nếu sử dụng Ruby 1.9: yehudakatz.com/2010/05/05/ Cách
xin lỗi

Câu trả lời:


179
str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a".force_encoding('ASCII-8BIT')
puts CGI.escape str


=> "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"

2
force_encoding('binary')có thể là một sự lựa chọn nhiều tài liệu hơn.
mu quá ngắn

63
Họ không tán thành phương pháp đó, sử dụng * CGI.escape* thay thế. -> http://www.ruby-forum.com/topic/207361#903709 . Bạn cũng có thể sử dụng URI.www_form_encode* URI.www_form_encode_component*, nhưng tôi chưa bao giờ sử dụng chúng
J-Rou

2
Không cần require 'open-uri'ở đây. Ý bạn là require 'uri'sao
pje

1
@ J-Rou, CGI.escape thể thoát khỏi toàn bộ URL, nó không có chọn lọc thoát truy vấn tham số, ví dụ, nếu bạn vượt qua 'a=&!@&b=&$^'để CGI.escape nó sẽ thoát khỏi toàn bộ điều có dải phân cách truy vấn &vì vậy đây có thể chỉ được sử dụng cho các giá trị truy vấn. Tôi đề nghị sử dụng addressableđá quý, nó là trí tuệ hơn làm việc với các url.
Alexander.Iljushkin

Tôi cần truy cập các tập tin trên máy chủ từ xa. Mã hóa với CGI không hoạt động, nhưng URI.encode đã làm việc rất tốt.
Ngày

82

Ngày nay, bạn nên sử dụng ERB::Util.url_encodehoặc CGI.escape. Sự khác biệt chính giữa chúng là xử lý không gian:

>> ERB::Util.url_encode("foo/bar? baz&")
=> "foo%2Fbar%3F%20baz%26"

>> CGI.escape("foo/bar? baz&")
=> "foo%2Fbar%3F+baz%26"

CGI.escapetheo thông số biểu mẫu CGI / HTML và cung cấp cho bạn một application/x-www-form-urlencodedchuỗi, yêu cầu các khoảng trắng được thoát đến +, trong khi ERB::Util.url_encodetheo RFC 3986 , yêu cầu chúng phải được mã hóa thành %20.

Xem " Sự khác biệt giữa URI.escape và CGI.escape là gì? " Để biết thêm thảo luận.


70
str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
require 'cgi'
CGI.escape(str)
# => "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"

Lấy từ nhận xét của @ J-Rou


11

Bạn có thể sử dụng Addressable::URIđá quý cho điều đó:

require 'addressable/uri'   
string = '\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a'
Addressable::URI.encode_component(string, Addressable::URI::CharacterClasses::QUERY)
# "%5Cx12%5Cx34%5Cx56%5Cx78%5Cx9a%5Cxbc%5Cxde%5Cxf1%5Cx23%5Cx45%5Cx67%5Cx89%5Cxab%5Cxcd%5Cxef%5Cx12%5Cx34%5Cx56%5Cx78%5Cx9a" 

Nó sử dụng định dạng hiện đại hơn CGI.escape, ví dụ, nó mã hóa đúng không gian dưới dạng %20và không phải là +dấu hiệu, bạn có thể đọc thêm trong " Loại ứng dụng / x-www-form-urlencoding " trên Wikipedia.

2.1.2 :008 > CGI.escape('Hello, this is me')
 => "Hello%2C+this+is+me" 
2.1.2 :009 > Addressable::URI.encode_component('Hello, this is me', Addressable::URI::CharacterClasses::QUERY)
 => "Hello,%20this%20is%20me" 

Cũng có thể làm như thế này: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"nếu không muốn sử dụng bất kỳ viên đá quý nào
Raccoon

5

Tôi đã tạo một viên ngọc để làm cho công cụ mã hóa URI sạch hơn để sử dụng trong mã của bạn. Nó chăm sóc mã hóa nhị phân cho bạn.

Chạy gem install uri-handler, sau đó sử dụng:

require 'uri-handler'

str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a".to_uri
# => "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"

Nó thêm chức năng chuyển đổi URI vào lớp String. Bạn cũng có thể truyền cho nó một đối số với chuỗi mã hóa tùy chọn mà bạn muốn sử dụng. Theo mặc định, nó đặt thành mã hóa 'nhị phân' nếu mã hóa UTF-8 thẳng không thành công.


2

Mã số:

str = "http://localhost/with spaces and spaces"
encoded = URI::encode(str)
puts encoded

Kết quả:

http://localhost/with%20spaces%20and%20spaces

Nếu máy chủ nhận cũ, nó có thể không đáp ứng tốt với CGI.escape. Đây vẫn là một thay thế hợp lệ.
mổ bụng

2

Ban đầu tôi chỉ cố thoát các ký tự đặc biệt trong một tên tệp, không phải trên đường dẫn, từ một chuỗi URL đầy đủ.

ERB::Util.url_encode không làm việc cho tôi sử dụng:

helper.send(:url_encode, "http://example.com/?a=\11\15")
# => "http%3A%2F%2Fexample.com%2F%3Fa%3D%09%0D"

Dựa trên hai câu trả lời trong " Tại sao URI.escape () được đánh dấu là lỗi thời và hằng số REGEXP :: UNSAFE này ở đâu? ", Có vẻ như URI::RFC2396_Parser#escapetốt hơn là sử dụng URI::Escape#escape. Tuy nhiên, cả hai đều cư xử giống nhau với tôi:

URI.escape("http://example.com/?a=\11\15")
# => "http://example.com/?a=%09%0D"
URI::Parser.new.escape("http://example.com/?a=\11\15")
# => "http://example.com/?a=%09%0D"

2

Nếu bạn muốn "mã hóa" một URL đầy đủ mà không phải suy nghĩ về việc tách thủ công nó thành các phần khác nhau, tôi đã tìm thấy các cách sau hoạt động theo cùng một cách mà tôi đã sử dụng URI.encode:

URI.parse(my_url).to_s
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.