Як URL-кодувати рядок у Ruby


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

Відповіді:


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')може бути більш самостійним документуванням.
mu занадто короткий

63
Вони застаріли, і CGI.escapeзамість цього використовувати * *. -> http://www.ruby-forum.com/topic/207489#903709 . Ви також повинні мати можливість використовувати URI.www_form_encode* URI.www_form_encode_component*, але я ніколи цього не використовував
J-Rou

2
Тут не потрібно require 'open-uri'. Ви мали на увазі require 'uri'?
пі

1
@ J-Rou, CGI.escape може вийти з цілої URL-адреси, вона не вибірково уникає параметрів запиту, наприклад, якщо ви перейдете 'a=&!@&b=&$^'до CGI.escape, вона дозволить уникнути всієї справи з розділювачами запитів, &щоб це могло використовуватися лише для значень запитів. Я пропоную використовувати addressableдорогоцінний камінь, це більш інтелектуальна робота з URL-адресами.
Олександр.Ілюшкін

Мені потрібно було отримати доступ до файлів на віддаленому сервері. Кодування за допомогою CGI не спрацювало, але URI.encode зробив роботу чудово.
Tashows

82

У наш час слід використовувати 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.

Див. " Яка різниця між 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дорогоцінний камінь для цього:

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а не як +знак, ви можете прочитати більше в " Застосування / 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"якщо не хочеться використовувати жодні дорогоцінні камені
Єнот

5

Я створив дорогоцінний камінь, щоб зробити речі кодування 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. Це все ще справедлива альтернатива.
цезартальви

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.