Jak sprawdzić, czy adres URL jest prawidłowy

94

Jak mogę sprawdzić, czy ciąg jest prawidłowym adresem URL?

Na przykład:

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

Jeśli to jest prawidłowy adres URL, jak mogę sprawdzić, czy jest on powiązany z plikiem obrazu?

Luca Romagnoli
źródło
podany adres URL wydaje się być bezwzględnym adresem URL, co masz na myśli w odniesieniu do pliku obrazu
johannes
I opublikował UriValidator ze specyfikacją .
JJD,

Odpowiedzi:

178

Użyj URImodułu dystrybuowanego z Rubim:

require 'uri'

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

Jak Alexander Günther powiedział w komentarzach, sprawdza, czy ciąg zawiera adres URL.

Aby sprawdzić, czy ciąg jest adresem URL, użyj:

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

Jeśli chcesz sprawdzić tylko adresy internetowe ( httplub https), użyj tego:

url =~ /\A#{URI::regexp(['http', 'https'])}\z/
Mikael S
źródło
25
To wydaje się nie działać: 'http://:5984/asdf' =~ URI::regexpi 'http::5984/asdf' =~ URI::regexpoba zwracają 0. Spodziewałem się, że zwrócą nil, ponieważ żaden z nich nie jest prawidłowym identyfikatorem URI.
wendt
4
Czy nie jest: 5984 port 5984 na hoście lokalnym?
mxcl,
3
W rzeczywistości sprawdza, czy zmienna zawiera prawidłowy adres URL. Akceptuje „ example com” jako prawidłowy adres URL. Ponieważ zawiera jeden. Ale nie jest pomocne, jeśli oczekujesz, że całość będzie adresem URL.
Alexander Günther
2
gotqn: To nie jest jednak prawidłowy adres URL zgodnie z RFC 1738.
Mikael S
12
Nie używaj tego, jest tak źle, że "http:"przechodzi to wyrażenie regularne.
smathy,
43

Podobnie jak w przypadku powyższych odpowiedzi, uważam, że użycie tego wyrażenia regularnego jest nieco dokładniejsze:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

Spowoduje to unieważnienie adresów URL ze spacjami, w przeciwieństwie do tego, URI.regexpco z jakiegoś powodu zezwala na spacje.

Niedawno znalazłem skrót, który jest dostępny dla różnych rgexps URI. Możesz uzyskać dostęp do dowolnego URI::DEFAULT_PARSER.regexp.keysbezpośrednio z URI::#{key}.

Na przykład do :ABS_URIwyrażenia regularnego można uzyskać dostęp z URI::ABS_URI.

jonuts
źródło
3
Jeśli planujesz używać URI.parse w dowolnym momencie, jest to zdecydowanie najlepsza droga. URI :: regexp dopasowuje określone adresy URL, które zakończą się niepowodzeniem przy późniejszym użyciu URI.parse. Dzięki za wskazówkę.
markquezada
Niestety jest to dostępne tylko w Rubim 1.9, a nie 1.8.
Steve Madsen
1
Ale to działa: /^#{URI.regexp}$/. Problem w tym, URI.regexpże nie zakotwicza. Łańcuch ze spacją nie weryfikuje spacji jako części identyfikatora URI, ale wszystko, co prowadzi do spacji. Jeśli ten fragment wygląda jak prawidłowy identyfikator URI, dopasowanie powiedzie się.
Steve Madsen
3
Stosowanie komentarza awendt do twoich propozycji: 'http://:5984/asdf' =~ URI::DEFAULT_PARSER.regexp[:ABS_URI]daje 0, a nie zero; 'http::5984/asdf'=~ URI::DEFAULT_PARSER.regexp[:ABS_URI]daje 0; 'http://:5984/asdf' =~ /^#{URI.regexp}$/daje 0; 'http::5984/asdf' =~ /^#{URI.regexp}$/daje również 0. Żadne z powyższych wyrażeń regularnych nie jest w pełni poprawne, jednak zawodzą one tylko w bardzo dziwnych sytuacjach iw większości przypadków nie jest to wielka sprawa.
skalee
1
FYI, URI::DEFAULT_PARSER.regexp[:ABS_URI]jest identyczne z/\A\s*#{URI::regexp}\s*\z/
Aidan
36

Problem z obecnymi odpowiedziami polega na tym, że identyfikator URI nie jest adresem URL .

Identyfikator URI można dalej sklasyfikować jako lokalizator, nazwę lub jedno i drugie. Termin „Uniform Resource Locator” (URL) odnosi się do podzbioru identyfikatorów URI, które oprócz identyfikowania zasobu, umożliwiają zlokalizowanie zasobu poprzez opisanie jego głównego mechanizmu dostępu (np. „Lokalizacji” w sieci).

Ponieważ adresy URL są podzbiorem identyfikatorów URI, jasne jest, że dopasowanie specyficzne dla identyfikatorów URI z powodzeniem dopasuje niepożądane wartości. Na przykład URN :

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

Biorąc to pod uwagę, o ile wiem, Ruby nie ma domyślnego sposobu analizowania adresów URL, więc najprawdopodobniej będziesz potrzebować klejnotu, aby to zrobić. Jeśli potrzebujesz dopasować adresy URL konkretnie w formacie HTTP lub HTTPS, możesz zrobić coś takiego:

uri = URI.parse(my_possible_url)
if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
  # do your stuff
end
fotanus
źródło
@Philip był pomocny i odpowiedni. Dziękuję Ci bardzo!
fotanus
2
uri.kind_of?(URI::HTTP)wydaje się być wystarczający w obu przypadkach (http i https), przynajmniej w Rubim 1.9.3.
Andrea Salicetti
nadal cierpi na problemy opisane przez @skalee pod odpowiedzią
jonutów
1
Podsumowując, URI.parse(string_to_be_checked).kind_of?(URI::HTTP)działa dobrze.
ben
Dodatkowo, bardzo częste błędy w wpisywaniu w naszej bazie danych pokazują, że ludzie mają tendencję do wstawiania wielu ukośników: http:///neopets.comco niestety jest również poprawne. Sprawdzanie obecności nazwy hosta rozwiązuje ten problem:uri = URI(str) ; %w[http https].include?(uri.scheme) && !uri.host.nil?
Shane
19

Wolę klejnot adresowalny . Odkryłem, że inteligentniej obsługuje adresy 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
David J.
źródło
3
Właśnie podałem Addressable :: URI.parse () najdziwniejsze ciągi znaków, aby zobaczyć, co odrzuca. Akceptuje szalone rzeczy. Jednak pierwszym ciągiem, którego nie zaakceptował, był „:-)”. Hmm.
mvw
1
Jak to się dzieje, że dostaje tyle głosów za? Addressable::URI.parsenie zwraca nil z nieprawidłowymi danymi wejściowymi.
garbagecollector
11

To jest dość stary wpis, ale pomyślałem, że mogę się do tego przyczynić:

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

Teraz możesz zrobić coś takiego:

if "http://www.omg.wtf".is_valid_url?
    p "huzzah!"
end
Wilhelm Murdoch
źródło
2
Działa to znacznie lepiej niż powyższe rozwiązania. Nie ma wymienionych powyżej zastrzeżeń, a także nie akceptuje adresów URL, takich jak javascript: alert ('spam').
bchurchill,
2
ale też pasuje http:/, co może nie być tym, czego chcesz.
Bo Jeanes
11

W moim przypadku używam tego wyrażenia regularnego:

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

Opcja:

  • i - bez rozróżniania wielkości liter
  • x - zignoruj ​​białe znaki w wyrażeniu regularnym

Możesz ustawić tę metodę, aby sprawdzić poprawność adresu 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

Aby z niego skorzystać:

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

Testowanie z niewłaściwymi adresami URL:

  • http://ruby3arabi - wynik jest nieprawidłowy
  • http://http://ruby3arabi.com - wynik jest nieprawidłowy
  • http:// - wynik jest nieprawidłowy
  • http://test.com\n<script src=\"nasty.js\"> (Po prostu zaznacz „<skrypt”)

Przetestuj z poprawnymi adresami URL:

  • http://ruby3arabi.com - wynik jest ważny
  • http://www.ruby3arabi.com - wynik jest ważny
  • https://www.ruby3arabi.com - wynik jest ważny
  • https://www.ruby3arabi.com/article/1 - wynik jest ważny
  • https://www.ruby3arabi.com/websites/58e212ff6d275e4bf9000000?locale=en - wynik jest ważny
Komsun K.
źródło
Następujące elementy są oznaczone jako prawidłowe:, "http://test.com\n<script src=\"nasty.js\">"a każda domena, która używa jednej z 683 domen TLD dłuższych niż 5 znaków lub ma dwa lub więcej następujących po sobie myślników, jest oznaczana jako nieprawidłowa. Dozwolone są numery portów spoza zakresu 0-65535. Adresy FTP i IP są oczywiście niedozwolone, ale warto o tym pamiętać.
aidan
1
z łatwością najlepsze najbardziej odpowiednie rozwiązanie do szybkiego sprawdzania adresu URL. dzięki
jakimś kierunku
4

To jest trochę stare, ale oto jak to robię. Użyj modułu URI Ruby, aby przeanalizować adres URL. Jeśli można go przeanalizować, jest to prawidłowy adres URL. (Ale to nie znaczy, że jest dostępny).

URI obsługuje wiele schematów, a ponadto możesz samodzielnie dodawać schematy niestandardowe:

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}

Zobacz dokumentację, aby uzyskać więcej informacji o module URI.

nyzm
źródło
Natknąłem się na to próbując naprawić segfault. Używanie URI.parsebyło właściwie przyczyną tego w Rubim 2.5.5 - przełączyłem się na odpowiedź @jonuts poniżej, jeśli nie masz nic przeciwko niektórym dziwnym przypadkom. Dla moich celów nie obchodziło mnie to, więc to było idealne.
el n00b
3

Ogólnie,

/^#{URI::regexp}$/

będzie działać dobrze, ale jeśli chcesz tylko dopasować httplub httpsmożesz przekazać je jako opcje do metody:

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

Zwykle działa to trochę lepiej, jeśli chcesz odrzucić protokoły takie jak ftp://.

user2275806
źródło
-2

Możesz również użyć wyrażenia regularnego, może coś takiego jak http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm zakładając, że to wyrażenie regularne jest poprawne (nie sprawdziłem go w pełni). pokazać ważność adresu 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
}

Powyższy przykład daje:

http://hello.it is valid
http:||bra.ziz not valid
Jamie
źródło
5
A co z programem mailto? Lub telnet, gopher, nntp, rsync, ssh lub jakikolwiek inny schemat? Adresy URL są nieco bardziej skomplikowane niż tylko HTTP i FTP.
mu jest za krótkie
Pisanie wyrażenia regularnego w celu weryfikacji adresów URL jest trudne. Po co się męczyć?
Rimian
@Rimian, musisz się tym przejmować, ponieważ URIw rzeczywistości wszystko, co można zrobić, jest zepsute. Zobacz komentarze pod tak wieloma pozytywnymi odpowiedziami powyżej. Nie jestem pewien, czy odpowiedź Janie jest prawidłowa, ale głosowanie za głosem, więc mam nadzieję, że ludzie rozważą to poważniej. TBH w końcu robię, url.start_with?("http://") || url.start_with?("https://")ponieważ potrzebuję tylko HTTP, a użytkownicy powinni być odpowiedzialni za używanie odpowiednich adresów URL.
akostadinov