Cách kiểm tra xem một URL có hợp lệ không


93

Làm cách nào để kiểm tra xem một chuỗi có phải là URL hợp lệ hay không?

Ví dụ:

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

Nếu đây là một URL hợp lệ, làm cách nào để kiểm tra xem nó có liên quan đến tệp hình ảnh không?


url mà bạn cung cấp có vẻ là một địa chỉ tuyệt đối, điều gì làm bạn có ý nghĩa tương đối với một tập tin hình ảnh
Johannes

Câu trả lời:


177

Sử dụng URImô-đun được phân phối với Ruby:

require 'uri'

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

Giống như Alexander Günther đã nói trong các nhận xét, nó kiểm tra xem một chuỗi có chứa URL hay không.

Để kiểm tra xem chuỗi có phải là URL hay không, hãy sử dụng:

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

Nếu bạn chỉ muốn kiểm tra các URL web ( httphoặc https), hãy sử dụng cái này:

url =~ /\A#{URI::regexp(['http', 'https'])}\z/

24
Điều đó dường như không hoạt động: 'http://:5984/asdf' =~ URI::regexp'http::5984/asdf' =~ URI::regexpcả hai đều trả về 0. Tôi đã mong đợi chúng trả về nil vì không ai trong số chúng là URI hợp lệ.
awendt

4
Không phải: 5984 cổng 5984 trên localhost?
mxcl

3
Nó thực sự kiểm tra xem một biến có chứa url hợp lệ hay không. Nó sẽ chấp nhận " example com" là một URL hợp lệ. Bởi vì nó chứa một. Nhưng sẽ không hữu ích nếu bạn mong đợi toàn bộ nội dung là URL.
Alexander Günther

2
gotqn: Tuy nhiên, đó không phải là một URL hợp lệ theo RFC 1738.
Mikael S

12
Đừng sử dụng cái này, nó quá tệ khi "http:"vượt qua regexp này.
smathy

43

Tương tự như các câu trả lời ở trên, tôi thấy sử dụng regex này chính xác hơn một chút:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

Điều đó sẽ làm mất hiệu lực các URL có khoảng trắng, trái ngược với URI.regexpnó cho phép khoảng trắng vì một số lý do.

Gần đây tôi đã tìm thấy một lối tắt được cung cấp cho các rgexps URI khác nhau. Bạn có thể truy cập URI::DEFAULT_PARSER.regexp.keystrực tiếp từ bất kỳ URI::#{key}.

Ví dụ, :ABS_URIregexp có thể được truy cập từ URI::ABS_URI.


3
Nếu bạn có kế hoạch sử dụng URI.parse tại bất kỳ thời điểm nào, thì đây chắc chắn là cách tốt nhất. URI :: regexp khớp với các URL nhất định sẽ bị lỗi khi sử dụng URI.parse sau này. Cảm ơn vì tiền hỗ trợ.
markquezada

Đáng buồn thay, điều này chỉ có sẵn trên Ruby 1.9, không phải 1.8.
Steve Madsen

1
Nhưng, công trình này: /^#{URI.regexp}$/. Vấn đề là URI.regexpnó không neo. Chuỗi có khoảng trắng không xác thực không gian như một phần của URI, nhưng mọi thứ dẫn đến khoảng trắng. Nếu phân đoạn đó trông giống như một URI hợp lệ, kết quả khớp sẽ thành công.
Steve Madsen

3
Áp dụng nhận xét của awendt cho các đề xuất của bạn: 'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]đưa ra 0, không phải số không; 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI]cho 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/cho 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/cũng cho 0. Không có regexps nào ở trên là chính xác hoàn toàn, tuy nhiên chúng chỉ thất bại trong những tình huống rất kỳ quặc và đây không phải là vấn đề lớn trong hầu hết các trường hợp.
skalee

1
FYI, URI::DEFAULT_PARSER.regexp[:ABS_URI]giống với/\A\s*#{URI::regexp}\s*\z/
aidan,

34

Vấn đề với các câu trả lời hiện tại là URI không phải là URL .

URI có thể được phân loại thêm dưới dạng định vị, tên hoặc cả hai. Thuật ngữ "Bộ định vị tài nguyên thống nhất" (URL) đề cập đến tập hợp con của các URI, ngoài việc xác định tài nguyên, còn cung cấp phương tiện định vị tài nguyên bằng cách mô tả cơ chế truy cập chính của nó (ví dụ: "vị trí" mạng của nó).

Vì URL là một tập hợp con của các URI, rõ ràng là đối sánh cụ thể cho các URI sẽ khớp thành công các giá trị không mong muốn. Ví dụ : URN :

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

Điều đó đang được nói, theo như tôi biết, Ruby không có cách mặc định để phân tích cú pháp URL, vì vậy rất có thể bạn sẽ cần một viên ngọc để làm như vậy. Nếu bạn cần khớp các URL cụ thể ở định dạng HTTP hoặc HTTPS, bạn có thể làm như sau:

uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
  # do your stuff
end

@Philip Vừa hữu ích vừa thích hợp. Cảm ơn rât nhiều!
fotanus

2
uri.kind_of?(URI::HTTP)dường như là đủ cho cả hai trường hợp (http và https), ít nhất là trong ruby ​​1.9.3.
Andrea Salicetti

vẫn phải chịu đựng những vấn đề được mô tả bởi @skalee dưới câu trả lời của jonuts
akostadinov

1
Tóm lại, URI.parse(string_to_be_checked).kind_of?(URI::HTTP)làm tốt công việc.
ben

19

Tôi thích đá quý Địa chỉ hơn . Tôi nhận thấy rằng nó xử lý URL thông minh hơn.

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
Tôi vừa cung cấp Addressable :: URI.parse () với các chuỗi kỳ lạ nhất để xem nó từ chối những gì. Nó chấp nhận những thứ điên rồ. Tuy nhiên chuỗi đầu tiên nó không chấp nhận là ":-)". Hừ!
mvw

1
Làm thế nào mà điều này lại nhận được nhiều ủng hộ như vậy? Addressable::URI.parsekhông trả về nil với đầu vào không hợp lệ.
garbagecollector 14/03/18

11

Đây là một mục khá cũ, nhưng tôi nghĩ tôi sẽ tiếp tục và đóng góp:

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

Bây giờ bạn có thể làm điều gì đó như:

if "http://www.omg.wtf".is_valid_url?
    p "huzzah!"
end

2
Này hoạt động nhiều hơn so với các giải pháp trên. Nó không có các cảnh báo được liệt kê ở trên và cũng không chấp nhận uris như javascript: alert ('spam').
bchurchill

2
nhưng nó cũng khớp http:/, có thể không như ý bạn muốn.
Bo Jeanes

10

Đối với tôi, tôi sử dụng cụm từ thông dụng này:

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

Lựa chọn:

  • i - trường hợp không nhạy cảm
  • x - bỏ qua khoảng trắng trong regex

Bạn có thể đặt phương pháp này để kiểm tra xác thực 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

Để dùng nó:

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

Kiểm tra với các URL sai:

  • http://ruby3arabi - kết quả không hợp lệ
  • http://http://ruby3arabi.com - kết quả không hợp lệ
  • http:// - kết quả không hợp lệ

Kiểm tra với các URL chính xác:

  • http://ruby3arabi.com - kết quả là hợp lệ
  • http://www.ruby3arabi.com - kết quả là hợp lệ
  • https://www.ruby3arabi.com - kết quả là hợp lệ
  • https://www.ruby3arabi.com/article/1 - kết quả là hợp lệ
  • https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - kết quả là hợp lệ

"http://test.com\n<script src=\"nasty.js\">"Tên miền sau được đánh dấu là hợp lệ: và bất kỳ tên miền nào sử dụng một trong 683 TLD dài hơn 5 ký tự hoặc có hai hoặc nhiều dấu gạch ngang liên tiếp, đều được đánh dấu là không hợp lệ. Số cổng bên ngoài phạm vi 0-65535 được cho phép. Địa chỉ FTP và IP rõ ràng là không được phép, nhưng đáng chú ý.
aidan

1
dễ dàng giải pháp tốt nhất áp dụng nhất ở đây để kiểm tra url nhanh chóng. cảm ơn
somedirection

4

Điều này hơi cũ một chút nhưng đây là cách tôi làm điều đó. Sử dụng mô-đun URI của Ruby để phân tích cú pháp URL. Nếu nó có thể được phân tích cú pháp thì đó là một URL hợp lệ. (Nhưng điều đó không có nghĩa là có thể truy cập được.)

URI hỗ trợ nhiều lược đồ, ngoài ra bạn có thể tự thêm các lược đồ tùy chỉnh:

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}

Xem tài liệu để biết thêm thông tin về mô-đun URI.


Tôi đã gặp lỗi này khi cố gắng sửa lỗi segfault. Việc sử dụng URI.parsethực sự là nguyên nhân của điều này trong Ruby 2.5.5 - Tôi đã chuyển sang câu trả lời @jonuts bên dưới nếu bạn không bận tâm đến một số trường hợp kỳ quặc. Đối với mục đích của tôi, tôi không quan tâm đến điều đó là lý tưởng.
el n00b

3

Nói chung,

/^#{URI::regexp}$/

sẽ hoạt động tốt, nhưng nếu bạn chỉ muốn đối sánh httphoặc https, bạn có thể chuyển chúng vào dưới dạng tùy chọn cho phương thức:

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

Điều đó có xu hướng hoạt động tốt hơn một chút, nếu bạn muốn từ chối các giao thức như ftp://.


-2

Bạn cũng có thể sử dụng regex, có thể giống như http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm giả sử regex này là chính xác (tôi chưa kiểm tra hoàn toàn) như sau hiển thị tính hợp lệ của 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
}

Ví dụ trên cho kết quả:

http://hello.it is valid
http:||bra.ziz not valid

5
Còn về lược đồ mailto? Hoặc telnet, gopher, nntp, rsync, ssh, hoặc bất kỳ chương trình nào khác? URL phức tạp hơn một chút so với HTTP và FTP.
mu quá ngắn

Viết regex để xác thực URL rất khó. Quan tâm làm gì?
Rimian

@Rimian, bạn phải bận tâm vì tất cả những URIgì có thể làm trên thực tế đã bị hỏng. Xem các bình luận bên dưới rất nhiều câu trả lời được ủng hộ ở trên. Không chắc câu trả lời của Janie có đúng không nhưng rất ủng hộ nên hy vọng mọi người hãy xem xét nó nghiêm túc hơn. TBH mà tôi kết thúc url.start_with?("http://") || url.start_with?("https://")vì tôi chỉ cần HTTP và người dùng phải có trách nhiệm sử dụng các URL thích hợp.
akostadinov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.