Come URL codificare una stringa in Ruby


135

Come faccio ad URI::encodeuna stringa come:

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

per ottenerlo in un formato come:

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

secondo RFC 1738?

Ecco cosa ho provato:

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

Anche:

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

Ho guardato tutto su Internet e non ho trovato il modo di farlo, anche se sono quasi sicuro che l'altro giorno l'ho fatto senza alcun problema.


1
Forse utile se si utilizza Ruby 1.9: yehudakatz.com/2010/05/05/…
apneadiving

Risposte:


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')potrebbe essere una scelta più autocompattante.
mu è troppo corto il

63
Hanno deprecato quel metodo, usare CGI.escapeinvece * *. -> http://www.ruby-forum.com/topic/207489#903709 . Dovresti anche essere in grado di usare URI.www_form_encode* URI.www_form_encode_component*, ma non li ho mai usati
J-Rou il

2
Non c'è bisogno di require 'open-uri'qui. Volevi dire require 'uri'?
pje,

1
@ J-Rou, CGI.escape può sfuggire all'intero URL, non sfugge in modo selettivo ai parametri della query, ad esempio, se passi 'a=&!@&b=&$^'a CGI.escape sfuggirà a tutto con i separatori di query in &modo da poterlo utilizzare solo per i valori di query. Suggerisco di usare addressablegem, è più intellettuale lavorare con gli URL.
Alexander.Iljushkin,

Avevo bisogno di accedere ai file sul server remoto. La codifica con CGI non ha funzionato, ma URI.encode ha funzionato bene.
Tashows,

82

Al giorno d'oggi, dovresti usare ERB::Util.url_encodeo CGI.escape. La differenza principale tra loro è la loro gestione degli spazi:

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

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

CGI.escapesegue le specifiche dei moduli CGI / HTML e fornisce una application/x-www-form-urlencodedstringa, in cui è necessario eseguire lo escape degli spazi +, mentre ERB::Util.url_encodesegue RFC 3986 , che richiede che siano codificati come %20.

Vedi " Qual è la differenza tra URI.escape e CGI.escape? " Per ulteriori discussioni.


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"

Tratto dal commento di @ J-Rou


11

Puoi usare Addressable::URIgem per questo:

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" 

Utilizza un formato più moderno, che CGI.escape, ad esempio, codifica correttamente lo spazio come %20e non come +segno, puoi leggere di più in " Il tipo di applicazione / x-www-form-urlencoded " su 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" 

Inoltre può fare così: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"se non vuoi usare gemme
Raccoon,

5

Ho creato un gioiello per rendere la codifica URI più pulita da usare nel tuo codice. Si occupa della codifica binaria per te.

Esegui gem install uri-handler, quindi 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"

Aggiunge la funzionalità di conversione URI nella classe String. Puoi anche passare un argomento con la stringa di codifica opzionale che desideri utilizzare. Per impostazione predefinita, imposta la codifica "binaria" se la codifica UTF-8 diretta non riesce.


2

Codice:

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

Risultato:

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

Se il server ricevente è vecchio, potrebbe non rispondere bene a CGI.escape. Questa è ancora una valida alternativa.
Cesartalves,

2

Inizialmente stavo cercando di sfuggire a caratteri speciali solo nel nome di un file, non nel percorso, da una stringa URL completa.

ERB::Util.url_encode non ha funzionato per il mio uso:

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

Basato su due risposte in " Perché URI.escape () è contrassegnato come obsoleto e dove si trova questa costante REGEXP :: UNSAFE? ", Sembra che URI::RFC2396_Parser#escapesia meglio dell'uso URI::Escape#escape. Tuttavia, entrambi si comportano allo stesso modo con me:

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

Se vuoi "codificare" un URL completo senza dover pensare a dividerlo manualmente nelle sue diverse parti, ho trovato quanto segue funzionava nello stesso modo in cui usavo URI.encode:

URI.parse(my_url).to_s
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.