Ruby url, кодирующая строку - PullRequest
125 голосов
/ 16 июля 2011

Как мне URI :: кодировать строку вроде:

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

Я посмотрел все об Интернете и не нашел (или, скорее, пропустил) способ сделать это, хотя я почти уверен, что на днях я сделал это без каких-либо проблем.

Спасибо!

Ответы [ 7 ]

166 голосов
/ 16 июля 2011
require 'uri'
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 URI::encode(str)

ОБНОВЛЕНИЕ: см. Комментарий ниже Строка кодировки URL Ruby

69 голосов
/ 31 января 2014
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

68 голосов
/ 18 февраля 2015

В настоящее время вы должны использовать ERB::Util.url_encode или CGI.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.

См. этот ответ для дальнейшего обсуждения.

8 голосов
/ 16 октября 2014

Для этого вы можете использовать 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, а не как +подписаться, вы можете прочитать больше в статья в Википедии

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" 
5 голосов
/ 25 января 2012

Я создал гем, чтобы сделать кодировку 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 в строкуучебный класс.Вы также можете передать ему аргумент с необязательной строкой кодирования, которую вы хотели бы использовать (по умолчанию устанавливается кодировка 'двоичная', если прямая кодировка UTF-8 не удалась).

2 голосов
/ 24 марта 2016

Первоначально я пытался экранировать специальные символы только в имени файла (но не в пути) из полной строки 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"

Основываясь на 2 ответах на различные вопросы SO , похоже, что 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"
0 голосов
/ 01 марта 2019

Если вы хотите «закодировать» полный URL-адрес, не думая о том, чтобы вручную разбить его на отдельные части, я обнаружил, что следующее работает так же, как и при использовании URI.encode:

URI.parse(my_url).to_s
...