ฉันจะตรวจสอบว่าสตริงเป็น URL ที่ถูกต้องได้อย่างไร
ตัวอย่างเช่น:
http://hello.it => yes
http:||bra.ziz, => no
หากนี่เป็น URL ที่ถูกต้องฉันจะตรวจสอบได้อย่างไรว่านี่สัมพันธ์กับไฟล์รูปภาพหรือไม่
ฉันจะตรวจสอบว่าสตริงเป็น URL ที่ถูกต้องได้อย่างไร
ตัวอย่างเช่น:
http://hello.it => yes
http:||bra.ziz, => no
หากนี่เป็น URL ที่ถูกต้องฉันจะตรวจสอบได้อย่างไรว่านี่สัมพันธ์กับไฟล์รูปภาพหรือไม่
คำตอบ:
ใช้URI
โมดูลที่แจกจ่ายด้วย Ruby:
require 'uri'
if url =~ URI::regexp
# Correct URL
end
เช่นเดียวกับที่Alexander Güntherกล่าวในความคิดเห็นจะตรวจสอบว่าสตริงมี URL หรือไม่
หากต้องการตรวจสอบว่าสตริงเป็น URL หรือไม่ให้ใช้:
url =~ /\A#{URI::regexp}\z/
หากคุณต้องการตรวจสอบเฉพาะ URL ของเว็บ ( http
หรือhttps
) ให้ใช้สิ่งนี้:
url =~ /\A#{URI::regexp(['http', 'https'])}\z/
'http://:5984/asdf' =~ URI::regexp
และ'http::5984/asdf' =~ URI::regexp
ทั้งคู่คืนค่า 0 ฉันคาดว่าพวกเขาจะคืนค่าศูนย์เนื่องจากไม่มี URI ที่ถูกต้อง
"http:"
ผ่าน regexp นี้
คล้ายกับคำตอบด้านบนฉันพบว่าการใช้ regex นี้จะแม่นยำกว่าเล็กน้อย:
URI::DEFAULT_PARSER.regexp[:ABS_URI]
ซึ่งจะทำให้ URL ที่มีช่องว่างไม่ถูกต้องURI.regexp
ซึ่งต่างจากที่อนุญาตให้มีช่องว่างด้วยเหตุผลบางประการ
ฉันเพิ่งพบทางลัดที่มีให้สำหรับ URI rgexps ที่แตกต่างกัน คุณสามารถเข้าถึงใด ๆ ของโดยตรงจากURI::DEFAULT_PARSER.regexp.keys
URI::#{key}
ยกตัวอย่างเช่น:ABS_URI
regexp URI::ABS_URI
สามารถเข้าถึงได้จาก
/^#{URI.regexp}$/
. ปัญหาคือที่URI.regexp
ยึดไม่ได้ สตริงที่มีช่องว่างไม่ได้ตรวจสอบความถูกต้องของช่องว่างว่าเป็นส่วนหนึ่งของ URI แต่ทุกอย่างที่นำไปสู่ช่องว่าง หากส่วนนั้นดูเหมือน URI ที่ถูกต้องการจับคู่จะสำเร็จ
'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]
ให้ 0 ไม่ใช่ศูนย์ 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI]
ให้ 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/
ให้ 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/
ให้ 0 เช่นกัน regexps ข้างต้นไม่ถูกต้องทั้งหมดอย่างไรก็ตามพวกเขาล้มเหลวในสถานการณ์ที่แปลกมากเท่านั้นและนี่ไม่ใช่เรื่องใหญ่ในกรณีส่วนใหญ่
URI::DEFAULT_PARSER.regexp[:ABS_URI]
เหมือนกับ/\A\s*#{URI::regexp}\s*\z/
ปัญหากับคำตอบที่ปัจจุบันคือว่าURI ที่ไม่ใช่ URL
URI สามารถจำแนกเพิ่มเติมได้ว่าเป็นตัวระบุตำแหน่งชื่อหรือทั้งสองอย่าง คำว่า "Uniform Resource Locator" (URL) หมายถึงชุดย่อยของ URI ที่นอกเหนือจากการระบุทรัพยากรแล้วยังมีวิธีการระบุตำแหน่งทรัพยากรโดยอธิบายกลไกการเข้าถึงหลัก (เช่น "ตำแหน่ง" ของเครือข่าย)
เนื่องจาก URL เป็นส่วนย่อยของ URI จึงเป็นที่ชัดเจนว่าการจับคู่เฉพาะสำหรับ URI จะจับคู่ค่าที่ไม่ต้องการได้สำเร็จ ตัวอย่างเช่นURN :
"urn:isbn:0451450523" =~ URI::regexp
=> 0
เท่าที่ฉันรู้มาว่า Ruby ไม่มีวิธีเริ่มต้นในการแยกวิเคราะห์ URL ดังนั้นคุณมักจะต้องมีอัญมณีเพื่อทำเช่นนั้น หากคุณต้องการจับคู่ URL โดยเฉพาะในรูปแบบ HTTP หรือ HTTPS คุณสามารถดำเนินการดังนี้:
uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
# do your stuff
end
uri.kind_of?(URI::HTTP)
ดูเหมือนว่าจะเพียงพอสำหรับทั้งสองกรณี (http และ https) อย่างน้อยก็ในทับทิม 1.9.3
URI.parse(string_to_be_checked).kind_of?(URI::HTTP)
ทำงานได้ดี
http:///neopets.com
ซึ่งก็ใช้ได้เช่นกัน การตรวจสอบการมีชื่อโฮสต์จะแก้ไขสิ่งนี้:uri = URI(str) ; %w[http https].include?(uri.scheme) && !uri.host.nil?
ฉันชอบอัญมณีแอดเดรสมากกว่า ฉันพบว่ามันจัดการ URL ได้อย่างชาญฉลาดมากขึ้น
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
Addressable::URI.parse
ไม่คืนค่าศูนย์ด้วยอินพุตที่ไม่ถูกต้อง
นี่เป็นรายการที่ค่อนข้างเก่า แต่ฉันคิดว่าจะดำเนินการต่อและมีส่วนร่วม:
String.class_eval do
def is_valid_url?
uri = URI.parse self
uri.kind_of? URI::HTTP
rescue URI::InvalidURIError
false
end
end
ตอนนี้คุณสามารถทำสิ่งต่างๆเช่น:
if "http://www.omg.wtf".is_valid_url?
p "huzzah!"
end
http:/
ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ
สำหรับฉันฉันใช้นิพจน์ทั่วไปนี้:
/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
ตัวเลือก:
i
- ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่x
- ละเว้นช่องว่างใน regexคุณสามารถตั้งค่าวิธีนี้เพื่อตรวจสอบความถูกต้องของ URL:
def valid_url?(url)
return false if url.include?("<script")
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
วิธีใช้:
valid_url?("http://stackoverflow.com/questions/1805761/check-if-url-is-valid-ruby")
การทดสอบด้วย URL ที่ไม่ถูกต้อง:
http://ruby3arabi
- ผลลัพธ์ไม่ถูกต้องhttp://http://ruby3arabi.com
- ผลลัพธ์ไม่ถูกต้องhttp://
- ผลลัพธ์ไม่ถูกต้องhttp://test.com\n<script src=\"nasty.js\">
(เพียงแค่ตรวจสอบ "<script")ทดสอบด้วย URL ที่ถูกต้อง:
http://ruby3arabi.com
- ผลลัพธ์ถูกต้องhttp://www.ruby3arabi.com
- ผลลัพธ์ถูกต้องhttps://www.ruby3arabi.com
- ผลลัพธ์ถูกต้องhttps://www.ruby3arabi.com/article/1
- ผลลัพธ์ถูกต้องhttps://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en
- ผลลัพธ์ถูกต้อง"http://test.com\n<script src=\"nasty.js\">"
และโดเมนใด ๆ ที่ใช้หนึ่งใน683 TLDที่มีความยาวมากกว่า 5 อักขระหรือมีขีดกลางสองตัวขึ้นไปติดต่อกันจะถูกทำเครื่องหมายว่าไม่ถูกต้อง อนุญาตให้ใช้หมายเลขพอร์ตนอกช่วง 0-65535 เห็นได้ชัดว่าไม่อนุญาตให้ใช้ FTP และที่อยู่ IP แต่ควรสังเกต
มันเก่าไปหน่อย แต่นี่คือวิธีที่ฉันทำ ใช้โมดูล URI ของ Ruby เพื่อแยกวิเคราะห์ URL หากสามารถแยกวิเคราะห์ได้แสดงว่าเป็น URL ที่ถูกต้อง (แต่ไม่ได้หมายความว่าสามารถเข้าถึงได้)
URI รองรับรูปแบบต่างๆและคุณสามารถเพิ่มรูปแบบที่กำหนดเองได้ด้วยตัวคุณเอง:
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}
ดูเอกสารสำหรับข้อมูลเพิ่มเติมเกี่ยวกับโมดูล URI
URI.parse
จริงๆแล้วการใช้เป็นสาเหตุของสิ่งนี้ใน Ruby 2.5.5 - ฉันเปลี่ยนเป็น @jonuts คำตอบด้านล่างหากคุณไม่สนใจกรณีแปลก ๆ ที่เกิดขึ้น สำหรับจุดประสงค์ของฉันฉันไม่สนใจดังนั้นมันจึงเหมาะ
โดยทั่วไปแล้ว
/^#{URI::regexp}$/
จะทำงานได้ดี แต่ถ้าคุณต้องการจับคู่เท่านั้นhttp
หรือhttps
คุณสามารถส่งผ่านสิ่งเหล่านั้นเป็นตัวเลือกไปยังวิธีการ:
/^#{URI::regexp(%w(http https))}$/
ที่มีแนวโน้มที่จะทำงานเล็ก ๆ น้อย ๆ ftp://
ที่ดีกว่าถ้าคุณต้องการที่จะปฏิเสธเช่นโปรโตคอล
คุณสามารถใช้ regex ได้เช่นhttp://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htmสมมติว่า regex นี้ถูกต้อง (ฉันยังไม่ได้ตรวจสอบทั้งหมด) สิ่งต่อไปนี้จะ แสดงความถูกต้องของ 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
}
ผลลัพธ์ตัวอย่างข้างต้น:
http://hello.it is valid
http:||bra.ziz not valid
URI
ทำได้คือเสียจริง ดูความคิดเห็นภายใต้คำตอบที่ได้รับการโหวตมากมายด้านบน ไม่แน่ใจว่าคำตอบของเจนี่ถูกต้องหรือไม่ แต่การโหวตเพิ่มหวังว่าผู้คนจะพิจารณาอย่างจริงจังมากขึ้น TBH ฉันทำurl.start_with?("http://") || url.start_with?("https://")
เพราะฉันต้องการ HTTP เท่านั้นและผู้ใช้ควรรับผิดชอบในการใช้ URL ที่เหมาะสม