วิธีตรวจสอบว่า URL ถูกต้องหรือไม่


95

ฉันจะตรวจสอบว่าสตริงเป็น URL ที่ถูกต้องได้อย่างไร

ตัวอย่างเช่น:

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

หากนี่เป็น URL ที่ถูกต้องฉันจะตรวจสอบได้อย่างไรว่านี่สัมพันธ์กับไฟล์รูปภาพหรือไม่


URL ที่คุณระบุดูเหมือนจะเป็น URL ที่แน่นอนคุณหมายถึงอะไรเมื่อเทียบกับไฟล์ภาพ
johannes

ฉันโพสต์UriValidator ที่มีรายละเอียด
JJD

คำตอบ:


179

ใช้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/

25
ดูเหมือนจะใช้ไม่ได้: 'http://:5984/asdf' =~ URI::regexpและ'http::5984/asdf' =~ URI::regexpทั้งคู่คืนค่า 0 ฉันคาดว่าพวกเขาจะคืนค่าศูนย์เนื่องจากไม่มี URI ที่ถูกต้อง
awendt

4
ไม่ใช่: 5984 พอร์ต 5984 บน localhost?
mxcl

3
ตรวจสอบว่าตัวแปรมี url ที่ถูกต้องหรือไม่ จะยอมรับ " example com" เป็น URL ที่ถูกต้อง เพราะประกอบด้วยหนึ่ง. แต่จะไม่เป็นประโยชน์หากคุณคาดหวังว่าสิ่งทั้งหมดจะเป็น URL
Alexander Günther

2
gotqn: นั่นไม่ใช่ URL ที่ถูกต้องตาม RFC 1738 แม้ว่า
Mikael S

12
อย่าใช้สิ่งนี้มันแย่มากที่"http:"ผ่าน regexp นี้
smathy

43

คล้ายกับคำตอบด้านบนฉันพบว่าการใช้ regex นี้จะแม่นยำกว่าเล็กน้อย:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

ซึ่งจะทำให้ URL ที่มีช่องว่างไม่ถูกต้องURI.regexpซึ่งต่างจากที่อนุญาตให้มีช่องว่างด้วยเหตุผลบางประการ

ฉันเพิ่งพบทางลัดที่มีให้สำหรับ URI rgexps ที่แตกต่างกัน คุณสามารถเข้าถึงใด ๆ ของโดยตรงจากURI::DEFAULT_PARSER.regexp.keysURI::#{key}

ยกตัวอย่างเช่น:ABS_URIregexp URI::ABS_URIสามารถเข้าถึงได้จาก


3
หากคุณวางแผนที่จะใช้ URI.parse ณ จุดใดก็ตามนี่เป็นวิธีที่แน่นอน URI :: regexp จับคู่ URL บางรายการที่จะล้มเหลวเมื่อใช้ URI.parse ในภายหลัง ขอบคุณสำหรับทิป.
markquezada

น่าเศร้าที่สิ่งนี้มีให้เฉพาะบน Ruby 1.9 ไม่ใช่ 1.8
Steve Madsen

1
แต่มันใช้งานได้: /^#{URI.regexp}$/. ปัญหาคือที่URI.regexpยึดไม่ได้ สตริงที่มีช่องว่างไม่ได้ตรวจสอบความถูกต้องของช่องว่างว่าเป็นส่วนหนึ่งของ URI แต่ทุกอย่างที่นำไปสู่ช่องว่าง หากส่วนนั้นดูเหมือน URI ที่ถูกต้องการจับคู่จะสำเร็จ
Steve Madsen

3
นำความคิดเห็นของ awendt ไปใช้กับข้อเสนอของคุณ: '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 ข้างต้นไม่ถูกต้องทั้งหมดอย่างไรก็ตามพวกเขาล้มเหลวในสถานการณ์ที่แปลกมากเท่านั้นและนี่ไม่ใช่เรื่องใหญ่ในกรณีส่วนใหญ่
skalee

1
FYI URI::DEFAULT_PARSER.regexp[:ABS_URI]เหมือนกับ/\A\s*#{URI::regexp}\s*\z/
aidan

36

ปัญหากับคำตอบที่ปัจจุบันคือว่า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

@ ฟิลิปเป็นประโยชน์และเหมาะสม ขอบคุณมาก!
fotanus

2
uri.kind_of?(URI::HTTP)ดูเหมือนว่าจะเพียงพอสำหรับทั้งสองกรณี (http และ https) อย่างน้อยก็ในทับทิม 1.9.3
Andrea Salicetti

ยังคงทนทุกข์ทรมานกับปัญหาที่อธิบายโดย @skalee ภายใต้คำตอบของ
jonuts

1
สรุป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?
เชน

19

ฉันชอบอัญมณีแอดเดรสมากกว่า ฉันพบว่ามันจัดการ 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

3
ฉันเพิ่งป้อน Addressable :: URI.parse () ด้วยสตริงที่แปลกประหลาดที่สุดเพื่อดูว่ามันปฏิเสธอะไร มันยอมรับเรื่องบ้าๆ อย่างไรก็ตามสตริงแรกที่ไม่ยอมรับคือ ":-)" อืม.
mvw

1
วิธีนี้ทำให้ได้รับการโหวตเพิ่มขึ้นมากมาย? Addressable::URI.parseไม่คืนค่าศูนย์ด้วยอินพุตที่ไม่ถูกต้อง
ร้านเก็บขยะ

11

นี่เป็นรายการที่ค่อนข้างเก่า แต่ฉันคิดว่าจะดำเนินการต่อและมีส่วนร่วม:

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

2
วิธีนี้ใช้งานได้ดีกว่าโซลูชันข้างต้นมาก ไม่มีคำเตือนที่ระบุไว้ข้างต้นและยังไม่ยอมรับ uris เช่น javascript: alert ('spam')
bchurchill

2
แต่มันก็ตรงกันhttp:/ซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ
Bo Jeanes

11

สำหรับฉันฉันใช้นิพจน์ทั่วไปนี้:

/^(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 แต่ควรสังเกต
aidan

1
เป็นทางออกที่ดีที่สุดสำหรับการตรวจสอบ url อย่างรวดเร็ว ขอบคุณ
Somedirection

4

มันเก่าไปหน่อย แต่นี่คือวิธีที่ฉันทำ ใช้โมดูล 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


ฉันวิ่งข้ามสิ่งนี้เพื่อพยายามแก้ไข segfault URI.parseจริงๆแล้วการใช้เป็นสาเหตุของสิ่งนี้ใน Ruby 2.5.5 - ฉันเปลี่ยนเป็น @jonuts คำตอบด้านล่างหากคุณไม่สนใจกรณีแปลก ๆ ที่เกิดขึ้น สำหรับจุดประสงค์ของฉันฉันไม่สนใจดังนั้นมันจึงเหมาะ
เอล n00b

3

โดยทั่วไปแล้ว

/^#{URI::regexp}$/

จะทำงานได้ดี แต่ถ้าคุณต้องการจับคู่เท่านั้นhttpหรือhttpsคุณสามารถส่งผ่านสิ่งเหล่านั้นเป็นตัวเลือกไปยังวิธีการ:

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

ที่มีแนวโน้มที่จะทำงานเล็ก ๆ น้อย ๆ ftp://ที่ดีกว่าถ้าคุณต้องการที่จะปฏิเสธเช่นโปรโตคอล


-2

คุณสามารถใช้ 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

5
แล้วโครงการ mailto ล่ะ? หรือ telnet, gopher, nntp, rsync, ssh หรือรูปแบบอื่น ๆ ? URL มีความซับซ้อนมากกว่า HTTP และ FTP เล็กน้อย
สั้นเกินไป

การเขียนนิพจน์ทั่วไปเพื่อตรวจสอบความถูกต้องของ URL เป็นเรื่องยาก รำคาญทำไม?
Rimian

@Rimian คุณต้องรบกวนเพราะสิ่งที่URIทำได้คือเสียจริง ดูความคิดเห็นภายใต้คำตอบที่ได้รับการโหวตมากมายด้านบน ไม่แน่ใจว่าคำตอบของเจนี่ถูกต้องหรือไม่ แต่การโหวตเพิ่มหวังว่าผู้คนจะพิจารณาอย่างจริงจังมากขึ้น TBH ฉันทำurl.start_with?("http://") || url.start_with?("https://")เพราะฉันต้องการ HTTP เท่านั้นและผู้ใช้ควรรับผิดชอบในการใช้ URL ที่เหมาะสม
akostadinov
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.