Cómo codificar URL una cadena en Ruby

135

¿Cómo me URI::encodegusta una cadena:

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

para obtenerlo en un formato como:

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

según RFC 1738?

Esto es lo que probé:

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

También:

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

Busqué todo en Internet y no he encontrado la manera de hacerlo, aunque estoy casi seguro de que el otro día lo hice sin ningún problema.

HRÓÐÓLFR
fuente
1
Quizás sea útil si usa Ruby 1.9: yehudakatz.com/2010/05/05/…
apneadiving

Respuestas:

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"
kain
fuente
2
force_encoding('binary')podría ser una opción más autodocumentada.
mu es demasiado corto
63
En desuso ese método, use * CGI.escape* en su lugar. -> http://www.ruby-forum.com/topic/207489#903709 . También deberías poder usar URI.www_form_encode* URI.www_form_encode_component*, pero nunca los he usado
J-Rou
2
No es necesario require 'open-uri'aquí. Quiso decir require 'uri'?
pje
1
@ J-Rou, CGI.escape puede escapar de la URL completa, no escapa selectivamente de los parámetros de consulta, por ejemplo, si pasa 'a=&!@&b=&$^'a CGI.escape, escapará de todo con separadores de consulta, &por lo que esto podría usarse solo para consultar valores. Sugiero usar addressablegem, es más intelectual trabajar con urls.
Alexander.Iljushkin
Necesitaba acceder a los archivos en el servidor remoto. La codificación con CGI no funcionó, pero URI.encode lo hizo bien.
Tashows
82

Hoy en día, debes usar ERB::Util.url_encodeo CGI.escape. La principal diferencia entre ellos es su manejo de espacios:

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

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

CGI.escapesigue la especificación de formularios CGI / HTML y le proporciona una application/x-www-form-urlencodedcadena, que requiere que se escapen espacios +, mientras que ERB::Util.url_encodesigue RFC 3986 , que requiere que se codifiquen como %20.

Consulte " ¿Cuál es la diferencia entre URI.escape y CGI.escape? " Para obtener más información.

Jenner La Fave
fuente
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"

Tomado del comentario de @ J-Rou

Jared Beck
fuente
11

Puedes usar Addressable::URIgema para eso:

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" 

Utiliza un formato más moderno que CGI.escape, por ejemplo, codifica correctamente el espacio como %20y no como +signo, puede leer más en " La aplicación / x-www-form-urlencoded type " en 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" 
Alexey Shein
fuente
También puede hacer esto: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"si no quiere usar gemas
Mapache
5

Creé una gema para hacer que las cosas de codificación URI sean más limpias para usar en su código. Se encarga de la codificación binaria por ti.

Corre gem install uri-handler, luego usa:

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"

Agrega la funcionalidad de conversión de URI a la clase String. También puede pasarle un argumento con la cadena de codificación opcional que le gustaría usar. De forma predeterminada, se establece en codificación 'binaria' si falla la codificación directa UTF-8.

Foomip
fuente
2

Código:

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

Resultado:

http://localhost/with%20spaces%20and%20spaces
Thiago Falcao
fuente
Si el servidor receptor es antiguo, es posible que no responda bien a CGI.escape. Esta sigue siendo una alternativa válida.
cesartalves
2

Originalmente estaba tratando de escapar de caracteres especiales solo en un nombre de archivo, no en la ruta, de una cadena URL completa.

ERB::Util.url_encode no funcionó para mi uso:

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

Basado en dos respuestas en " ¿Por qué URI.escape () está marcado como obsoleto y dónde está esta constante REGEXP :: UNSAFE? ", Parece que URI::RFC2396_Parser#escapees mejor que usarlo URI::Escape#escape. Sin embargo, ambos se comportan igual para mí:

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"
kangkyu
fuente
2

Si desea "codificar" una URL completa sin tener que pensar en dividirla manualmente en sus diferentes partes, descubrí que lo siguiente funcionó de la misma manera que solía usar URI.encode:

URI.parse(my_url).to_s
Glenn 'devalias'
fuente