Cara URL menyandikan string di Ruby

135

Bagaimana URI::encodecara string seperti:

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

untuk mendapatkannya dalam format seperti:

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

sesuai RFC 1738?

Inilah yang saya coba:

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

Juga:

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

Saya mencari semua tentang internet dan belum menemukan cara untuk melakukan ini, walaupun saya hampir positif bahwa beberapa hari yang lalu saya melakukan ini tanpa masalah sama sekali.

HRÓÐÓLFR
sumber
1
Mungkin berguna jika menggunakan Ruby 1.9: yehudakatz.com/2010/05/05/...
apneadiving

Jawaban:

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
sumber
2
force_encoding('binary')mungkin menjadi pilihan yang lebih banyak mendokumentasikan diri.
mu terlalu pendek
63
Mereka tidak lagi menggunakan metode itu, CGI.escapesebaliknya menggunakan * *. -> http://www.ruby-forum.com/topic/207489#903709 . Anda juga harus dapat menggunakan URI.www_form_encode* URI.www_form_encode_component*, tetapi saya tidak pernah menggunakan itu
J-Rou
2
Tidak perlu ke require 'open-uri'sini. Apakah maksud Anda require 'uri'?
pje
1
@ J-Rou, CGI.escape dapat keluar dari seluruh URL, tidak selektif lolos dari parameter kueri, misalnya, jika Anda meneruskan 'a=&!@&b=&$^'ke CGI.escape itu akan lolos semuanya dengan pemisah kueri &sehingga ini hanya dapat digunakan untuk nilai kueri. Saya sarankan menggunakan addressablepermata, itu lebih intelektual bekerja dengan url.
Alexander.Iljushkin
Saya perlu mengakses file di server jauh. Pengkodean dengan CGI tidak berhasil, tetapi URI.encode berhasil dengan baik.
Tashows
82

Saat ini, Anda harus menggunakan ERB::Util.url_encodeatau CGI.escape. Perbedaan utama di antara mereka adalah penanganan ruang mereka:

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

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

CGI.escapemengikuti spec formulir CGI / HTML dan memberi Anda sebuah application/x-www-form-urlencodedstring, yang membutuhkan spasi untuk melarikan diri +, sedangkan ERB::Util.url_encodemengikuti RFC 3986 , yang mengharuskan mereka untuk dikodekan sebagai %20.

Lihat " Apa perbedaan antara URI.escape dan CGI.escape? " Untuk diskusi lebih lanjut.

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

Diambil dari komentar @ J-Rou

Jared Beck
sumber
11

Anda dapat menggunakan Addressable::URIpermata untuk itu:

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" 

Ini menggunakan format yang lebih modern, daripada CGI.escape, misalnya, itu benar menyandikan ruang sebagai %20dan bukan sebagai +tanda, Anda dapat membaca lebih lanjut di " Jenis aplikasi / x-www-form-urlencoded " di 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
sumber
Juga dapat melakukan hal ini: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"jika tidak ingin menggunakan permata
Raccoon
5

Saya membuat permata untuk membuat penyandian URI lebih bersih untuk digunakan dalam kode Anda. Ini menangani pengodean biner untuk Anda.

Jalankan gem install uri-handler, lalu gunakan:

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"

Itu menambahkan fungsi konversi URI ke dalam kelas String. Anda juga bisa memberikan argumen dengan string penyandian opsional yang ingin Anda gunakan. Secara default ia mengatur ke encoding 'binary' jika pengkodean lurus UTF-8 gagal.

Foomip
sumber
2

Kode:

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

Hasil:

http://localhost/with%20spaces%20and%20spaces
Thiago Falcao
sumber
Jika server penerima sudah tua, itu mungkin tidak merespons dengan baik untuk CGI.escape. Ini masih merupakan alternatif yang valid.
cesartalves
2

Awalnya saya mencoba melarikan diri karakter khusus hanya dalam nama file, bukan di jalur, dari string URL lengkap.

ERB::Util.url_encode tidak berfungsi untuk saya gunakan:

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

Berdasarkan dua jawaban di " Mengapa URI.escape () ditandai sebagai usang dan di mana REGEXP :: UNSAFE ini konstan? ", Sepertinya URI::RFC2396_Parser#escapelebih baik daripada menggunakan URI::Escape#escape. Namun, mereka berdua berperilaku sama dengan saya:

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
sumber
2

Jika Anda ingin "menyandikan" URL lengkap tanpa harus memikirkan membelahnya secara manual menjadi bagian-bagian yang berbeda, saya menemukan yang berikut ini berfungsi dengan cara yang sama seperti yang saya gunakan URI.encode:

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