如何在Ruby中对字符串进行URL编码


135

我如何URI::encode像这样的字符串:

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

以如下格式获取它:

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

根据RFC 1738?

这是我尝试过的:

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>'

也:

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>'

我四处寻找有关互联网的信息,但还没有找到解决方法,尽管我几乎肯定地说,前几天我做到了这一点,没有任何麻烦。


1
也许有用的,如果使用Ruby 1.9:yehudakatz.com/2010/05/05/...
apneadiving

Answers:


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')可能是一个更具自我证明的选择。
亩太短了

63
他们不赞成使用该方法,而应使用* CGI.escape*。-> http://www.ruby-forum.com/topic/207489#903709。你也应该能够使用 URI.www_form_encode* URI.www_form_encode_component*,但我从来没有使用过这些
J-柔

2
没有必要require 'open-uri'在这里。你是说require 'uri'
2013年

1
@ J-Rou,CGI.escape可以转义整个URL,它不会选择性地转义查询参数,例如,如果传递'a=&!@&b=&$^'给CGI.escape,它将转义带有查询分隔符的全部内容,&因此只能用于查询值。我建议使用addressablegem,它对URL更具智能。
Alexander.Iljushkin

我需要访问远程服务器上的文件。使用CGI编码无法正常工作,但是URI.encode可以正常工作。
塔秀(Tashows)

82

现在,您应该使用ERB::Util.url_encodeCGI.escape。它们之间的主要区别在于它们对空间的处理:

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

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

CGI.escape遵循CGI / HTML格式规范,并为您提供一个application/x-www-form-urlencoded字符串,该字符串要求将空格转义为+,而ERB::Util.url_encode遵循RFC 3986则要求将其编码为%20

有关更多讨论,请参见“ URI.escape和CGI.escape有什么区别? ”。


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"

摘自@ J-Rou的评论


11

您可以Addressable::URI为此使用gem:

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" 

它使用的格式比现在更现代,CGI.escape例如,它正确地将空格编码%20+符号而不是符号,您可以在Wikipedia上的“ application / x-www-form-urlencoded type ”中阅读更多内容。

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" 

也可以这样: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"如果不想使用任何宝石
Raccoon

5

我创建了一个gem,使URI编码的内容更干净,可以在您的代码中使用。它为您处理二进制编码。

运行gem install uri-handler,然后使用:

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"

它将URI转换功能添加到String类中。您还可以向其传递一个参数,该参数包含要使用的可选编码字符串。默认情况下,如果直接UTF-8编码失败,它将设置为编码“二进制”。


2

码:

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

结果:

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

如果接收服务器较旧,则它对CGI.escape的响应可能不佳。这仍然是有效的选择。
cesartalves

2

我最初试图从完整的URL字符串中仅转义文件名中的特殊字符,而不是路径中的特殊字符。

ERB::Util.url_encode 不适合我使用:

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

根据“ 为什么URI.escape()标记为过时以及此REGEXP :: UNSAFE常量在哪里? ”中的两个答案,它看起来URI::RFC2396_Parser#escape比使用更好URI::Escape#escape。但是,它们对我的行为都相同:

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

如果您想“编码”完整的URL,而不必考虑手动将其拆分为不同的部分,那么我发现以下内容的工作方式与以前相同URI.encode

URI.parse(my_url).to_s
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.