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.


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"

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.


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


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" 

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.


2

Kode:

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

Hasil:

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

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"

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.