Bagaimana cara memeriksa apakah URL valid

94

Bagaimana cara memeriksa apakah sebuah string adalah URL yang valid?

Sebagai contoh:

http://hello.it => yes
http:||bra.ziz, => no

Jika ini adalah URL yang valid, bagaimana cara memeriksa apakah ini terkait dengan file gambar?

Luca Romagnoli
sumber
url yang Anda berikan tampaknya merupakan url mutlak, apa yang Anda maksud dengan file gambar
johannes
Saya memposting UriValidator dengan spesifikasi .
JJD

Jawaban:

178

Gunakan URImodul yang didistribusikan dengan Ruby:

require 'uri'

if url =~ URI::regexp
    # Correct URL
end

Seperti yang dikatakan Alexander Günther di komentar, ia memeriksa apakah sebuah string berisi URL.

Untuk memeriksa apakah string itu URL, gunakan:

url =~ /\A#{URI::regexp}\z/

Jika Anda hanya ingin memeriksa URL web ( httpatau https), gunakan ini:

url =~ /\A#{URI::regexp(['http', 'https'])}\z/
Mikael S
sumber
25
Tampaknya tidak berhasil: 'http://:5984/asdf' =~ URI::regexpdan 'http::5984/asdf' =~ URI::regexpkeduanya mengembalikan 0. Saya berharap mereka mengembalikan nihil karena tidak ada URI yang valid.
berakhir
4
Bukankah: 5984 port 5984 di localhost?
mxcl
3
Ini benar-benar memeriksa apakah variabel berisi url yang valid. Ini akan menerima " contoh com" sebagai URL yang valid. Karena mengandung satu. Tetapi tidak membantu jika Anda mengharapkan semuanya menjadi URL.
Alexander Günther
2
gotqn: Itu bukan URL yang valid menurut RFC 1738.
Mikael S
12
Jangan gunakan ini, ini sangat buruk yang "http:"melewati regexp ini.
smathy
43

Mirip dengan jawaban di atas, saya merasa menggunakan regex ini sedikit lebih akurat:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

Itu akan membuat URL dengan spasi tidak valid, bukan URI.regexpyang mengizinkan spasi karena beberapa alasan.

Saya baru saja menemukan pintasan yang disediakan untuk rgexps URI yang berbeda. Anda dapat mengakses salah satu URI::DEFAULT_PARSER.regexp.keyslangsung dari URI::#{key}.

Misalnya, :ABS_URIregexp dapat diakses dari URI::ABS_URI.

jonuts
sumber
3
Jika Anda berencana menggunakan URI.parse kapan saja, ini pasti cara yang tepat. URI :: regexp cocok dengan URL tertentu yang akan gagal saat menggunakan URI.parse nanti. Terima kasih atas tipnya.
markquezada
Sayangnya, ini hanya tersedia di Ruby 1.9, bukan 1.8.
Steve Madsen
1
Tapi, ini bekerja: /^#{URI.regexp}$/. Masalahnya adalah itu URI.regexptidak berlabuh. Sebuah string dengan spasi tidak memvalidasi spasi sebagai bagian dari URI, tetapi semua yang mengarah ke spasi. Jika fragmen tersebut terlihat seperti URI yang valid, kecocokan berhasil.
Steve Madsen
3
Menerapkan komentar awendt untuk proposal Anda: 'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]memberi 0, bukan nihil; 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI]memberikan 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/memberikan 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/memberikan 0 juga. Tidak satu pun dari regex di atas yang sepenuhnya benar, namun mereka gagal hanya dalam situasi yang sangat aneh dan ini bukan masalah besar dalam banyak kasus.
skalee
1
FYI, URI::DEFAULT_PARSER.regexp[:ABS_URI]identik dengan/\A\s*#{URI::regexp}\s*\z/
aidan
36

Masalah dengan jawaban saat ini adalah bahwa URI bukanlah URL .

URI selanjutnya dapat diklasifikasikan sebagai pencari lokasi, nama, atau keduanya. Istilah "Uniform Resource Locator" (URL) mengacu pada subset URI yang, selain mengidentifikasi sumber daya, menyediakan cara untuk menemukan sumber daya dengan menjelaskan mekanisme akses utamanya (misalnya, "lokasi" jaringannya).

Karena URL adalah bagian dari URI, jelas bahwa pencocokan khusus untuk URI akan berhasil mencocokkan nilai yang tidak diinginkan. Misalnya, URN :

 "urn:isbn:0451450523" =~ URI::regexp
 => 0 

Karena itu, sejauh yang saya tahu, Ruby tidak memiliki cara default untuk mengurai URL, jadi Anda kemungkinan besar memerlukan permata untuk melakukannya. Jika Anda perlu mencocokkan URL secara khusus dalam format HTTP atau HTTPS, Anda dapat melakukan sesuatu seperti ini:

uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
  # do your stuff
end
fotanus.dll
sumber
@Philip Sangat membantu dan sesuai. Terima kasih banyak!
fotanus
2
uri.kind_of?(URI::HTTP)tampaknya cukup untuk kedua kasus (http dan https), setidaknya di ruby ​​1.9.3.
Andrea Salicetti
masih menderita masalah yang dijelaskan oleh @skalee di bawah jawaban
jonuts
1
Ringkasan, URI.parse(string_to_be_checked).kind_of?(URI::HTTP)melakukan pekerjaan dengan baik.
ben
Selain itu, kesalahan ketik yang sangat umum di database kami menunjukkan bahwa orang cenderung melakukan banyak garis miring:, http:///neopets.comyang sayangnya juga valid. Memeriksa keberadaan nama host memperbaiki ini:uri = URI(str) ; %w[http https].include?(uri.scheme) && !uri.host.nil?
Shane
19

Saya lebih suka permata Addressable . Saya telah menemukan bahwa ini menangani URL dengan lebih cerdas.

require 'addressable/uri'

SCHEMES = %w(http https)

def valid_url?(url)
  parsed = Addressable::URI.parse(url) or return false
  SCHEMES.include?(parsed.scheme)
rescue Addressable::URI::InvalidURIError
  false
end
David J.
sumber
3
Saya baru saja memberi makan Addressable :: URI.parse () dengan string paling aneh untuk melihat apa yang ditolaknya. Itu menerima hal-hal gila. Namun string pertama yang tidak diterima adalah ":-)". Hmm.
mvw
1
Bagaimana ini mendapatkan begitu banyak suara positif? Addressable::URI.parsetidak mengembalikan nol dengan masukan yang tidak valid.
garbagecollector
11

Ini adalah entri yang cukup lama, tetapi saya pikir saya akan terus maju dan berkontribusi:

String.class_eval do
    def is_valid_url?
        uri = URI.parse self
        uri.kind_of? URI::HTTP
    rescue URI::InvalidURIError
        false
    end
end

Sekarang Anda dapat melakukan sesuatu seperti:

if "http://www.omg.wtf".is_valid_url?
    p "huzzah!"
end
Wilhelm Murdoch
sumber
2
Ini bekerja jauh lebih baik daripada solusi di atas. Itu tidak memiliki peringatan yang tercantum di atas, dan juga tidak menerima uris seperti javascript: alert ('spam').
bchurchill
2
tetapi juga cocok http:/, yang mungkin bukan yang Anda inginkan.
Bo Jeanes
10

Bagi saya, saya menggunakan ekspresi reguler ini:

/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix

Pilihan:

  • i - case insensitive
  • x - abaikan spasi kosong di regex

Anda dapat menyetel metode ini untuk memeriksa validasi URL:

def valid_url?(url)
  url_regexp = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
  url =~ url_regexp ? true : false
end

Untuk menggunakannya:

valid_url?("http://stackoverflow.com/questions/1805761/check-if-url-is-valid-ruby")

Menguji dengan URL yang salah:

  • http://ruby3arabi - hasil tidak valid
  • http://http://ruby3arabi.com - hasil tidak valid
  • http:// - hasil tidak valid

Uji dengan URL yang benar:

  • http://ruby3arabi.com - hasilnya valid
  • http://www.ruby3arabi.com - hasilnya valid
  • https://www.ruby3arabi.com - hasilnya valid
  • https://www.ruby3arabi.com/article/1 - hasilnya valid
  • https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - hasilnya valid
Komsun K.
sumber
Berikut ini ditandai sebagai valid:, "http://test.com\n<script src=\"nasty.js\">"dan domain apa pun yang menggunakan salah satu dari 683 TLD yang lebih dari 5 karakter, atau memiliki dua atau lebih tanda hubung berturut-turut, ditandai sebagai tidak valid. Nomor port di luar kisaran 0-65535 diperbolehkan. Alamat FTP dan IP jelas tidak diizinkan, tetapi perlu diperhatikan.
aidan
1
dengan mudah solusi terbaik yang paling dapat diterapkan di sini untuk pemeriksaan url cepat. terima kasih
somedirection
4

Ini agak tua tapi beginilah cara saya melakukannya. Gunakan modul URI Ruby untuk mengurai URL. Jika dapat diurai maka itu adalah URL yang valid. (Tapi itu tidak berarti dapat diakses.)

URI mendukung banyak skema, ditambah lagi Anda dapat menambahkan skema kustom sendiri:

irb> uri = URI.parse "http://hello.it" rescue nil
=> #<URI::HTTP:0x10755c50 URL:http://hello.it>

irb> uri.instance_values
=> {"fragment"=>nil,
 "registry"=>nil,
 "scheme"=>"http",
 "query"=>nil,
 "port"=>80,
 "path"=>"",
 "host"=>"hello.it",
 "password"=>nil,
 "user"=>nil,
 "opaque"=>nil}

irb> uri = URI.parse "http:||bra.ziz" rescue nil
=> nil


irb> uri = URI.parse "ssh://hello.it:5888" rescue nil
=> #<URI::Generic:0x105fe938 URL:ssh://hello.it:5888>
[26] pry(main)> uri.instance_values
=> {"fragment"=>nil,
 "registry"=>nil,
 "scheme"=>"ssh",
 "query"=>nil,
 "port"=>5888,
 "path"=>"",
 "host"=>"hello.it",
 "password"=>nil,
 "user"=>nil,
 "opaque"=>nil}

Lihat dokumentasi untuk informasi lebih lanjut tentang modul URI.

nyzm
sumber
Saya menemukan ini mencoba untuk memperbaiki segfault. Menggunakan URI.parsesebenarnya penyebab ini di Ruby 2.5.5 - Saya beralih ke jawaban @jonuts di bawah ini jika Anda tidak keberatan dengan beberapa kasus aneh yang gagal. Untuk tujuan saya, saya tidak peduli jadi itu ideal.
el n00b
3

Secara umum,

/^#{URI::regexp}$/

akan bekerja dengan baik, tetapi jika Anda hanya ingin mencocokkan httpatau https, Anda dapat meneruskannya sebagai opsi ke metode:

/^#{URI::regexp(%w(http https))}$/

Itu cenderung bekerja sedikit lebih baik, jika Anda ingin menolak protokol seperti ftp://.

pengguna2275806
sumber
-2

Anda juga dapat menggunakan regex, mungkin sesuatu seperti http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm dengan asumsi regex ini benar (saya belum sepenuhnya memeriksanya) tunjukkan validitas url.

url_regex = Regexp.new("((https?|ftp|file):((//)|(\\\\))+[\w\d:\#@%/;$()~_?\+-=\\\\.&]*)")

urls = [
    "http://hello.it",
    "http:||bra.ziz"
]

urls.each { |url|
    if url =~ url_regex then
        puts "%s is valid" % url
    else
        puts "%s not valid" % url
    end
}

Output contoh di atas:

http://hello.it is valid
http:||bra.ziz not valid
Jamie
sumber
5
Bagaimana dengan skema mailto? Atau telnet, gopher, nntp, rsync, ssh, atau skema lainnya? URL sedikit lebih rumit dari sekedar HTTP dan FTP.
mu terlalu pendek
Menulis regex untuk memvalidasi URL itu sulit. Mengapa mengganggu?
Rimian
@Rimian, harus repot karena semua yang URIbisa dilakukan malah rusak. Lihat komentar di bawah begitu banyak jawaban positif di atas. Tidak yakin apakah jawaban Janie benar tetapi upvoting jadi mudah-mudahan orang mempertimbangkannya lebih serius. TBH akhirnya saya lakukan url.start_with?("http://") || url.start_with?("https://")karena saya hanya perlu HTTP dan pengguna harus bertanggung jawab untuk menggunakan URL yang tepat.
akostadinov