Як перевірити правильність URL-адреси


94

Як я можу перевірити, чи рядок є дійсною URL-адресою?

Наприклад:

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

Якщо це дійсна URL-адреса, як я можу перевірити, чи є вона відносно файлу зображення?


надана вами URL-адреса видається абсолютною URL-адресою, що ви маєте на увазі стосовно файлу зображення
johannes

Відповіді:


178

Використовуйте URIмодуль, розподілений разом з Ruby:

require 'uri'

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

Як сказав Олександр Гюнтер у коментарях, він перевіряє, чи містить рядок 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-адреса.
Олександр Гюнтер

2
gotqn: Це не є дійсною URL-адресою згідно з RFC 1738.
Mikael S

12
Не використовуйте це, це настільки погано, що "http:"проходить цей регулярний вираз.
smathy

43

Подібно до відповідей вище, я вважаю, що використання цього регулярного виразу є дещо точнішим:

URI::DEFAULT_PARSER.regexp[:ABS_URI]

Це призведе до анулювання URL-адрес із пробілами, на відміну від URI.regexpяких з якихось причин допускає пробіли.

Нещодавно я знайшов ярлик, який надається для різних rgexps URI. Ви можете отримати доступ до будь-якого URI::DEFAULT_PARSER.regexp.keysбезпосередньо з URI::#{key}.

Наприклад, :ABS_URIрегулярний вираз можна отримати з URI::ABS_URI.


3
Якщо ви плануєте використовувати URI.parse в будь-який момент, це, безумовно, шлях. URI :: regexp відповідає певним URL-адресам, які не вдасться пізніше використовувати URI.parse. Дякую за підказку.
markquezada

На жаль, це доступно лише на Ruby 1.9, а не 1.8.
Стів Медсен,

1
Але це працює: /^#{URI.regexp}$/. Біда в тому, що URI.regexpне закріплюється. Рядок з пробілом не перевіряє пробіл як частину URI, а все, що веде до пробілу. Якщо цей фрагмент виглядає як дійсний URI, збіг вдається.
Стів Медсен,

3
Застосування коментаря Авендта до ваших пропозицій: '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. Жоден з наведених вище регулярних виразів не є повністю правильним, однак вони дають збій лише у дуже дивних ситуаціях, і це в більшості випадків не є великою проблемою.
skalee

1
FYI, URI::DEFAULT_PARSER.regexp[:ABS_URI]ідентично/\A\s*#{URI::regexp}\s*\z/
aidan

36

Проблема поточних відповідей полягає в тому, що URI не є URL-адресою .

URI може бути далі класифікований як локатор, назва або як те, так і інше. Термін "Уніфікований локатор ресурсів" (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

@Philip Був і корисним, і доречним. Велике спасибі!
fotanus

2
uri.kind_of?(URI::HTTP)здається достатнім для обох випадків (http і https), принаймні в ruby ​​1.9.3.
Андреа Салікетті,

досі страждає від проблем, описаних @skalee під відповіддю джонутів
Акостадінов

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 ('спам').
bchurchill

2
але це також відповідає http:/, що може бути не тим, що ви хочете.
Bo Jeanes

10

Для мене я використовую цей регулярний вираз:

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

Варіант:

  • i - регістр не чутливий
  • x - ігнорувати пробіли в регулярному виразі -

Ви можете встановити цей метод для перевірки перевірки 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

Щоб використовувати його:

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

Тестування з помилковими URL-адресами:

  • http://ruby3arabi - результат недійсний
  • http://http://ruby3arabi.com - результат недійсний
  • http:// - результат недійсний

Перевірте правильні 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 доменів верхнього рівня, що має більше 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 нижче, якщо ви не проти, щоб пропали якісь дивні випадки. Для моїх цілей мені було байдуже, тому це було ідеально.
el n00b

3

В загальному,

/^#{URI::regexp}$/

буде працювати добре, але якщо ви хочете лише відповідати httpабо https, ви можете передати їх як варіанти методу:

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

Це, як правило, працює трохи краще, якщо ви хочете відхилити протоколи типу ftp://.


-2

Ви також можете використовувати регулярний вираз, можливо щось на зразок http://www.geekzilla.co.uk/View2D3B0109-C1B2-4B4E-BFFD-E8088CBC85FD.htm, припускаючи, що цей регулярний вираз правильний (я не перевірив його повністю), наступне буде показати дійсність 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
А як щодо схеми поштової розсилки? Або telnet, gopher, nntp, rsync, ssh або будь-яку іншу схему? URL-адреси трохи складніші, ніж просто HTTP та FTP.
мю занадто коротке

Написати регулярний вираз для перевірки URL-адрес важко. Навіщо турбуватись?
Ріміан

@Rimian, ти повинен турбуватись, бо все, що URIможна зробити, насправді зламане. Див. Коментарі під стільки прихильних відповідей вище. Не впевнений, що відповідь Дженні правильна, але голосую, тому, сподіваємось, люди розглядають це більш серйозно. TBH Я в підсумку роблю, url.start_with?("http://") || url.start_with?("https://")тому що мені потрібен лише HTTP, і користувачі повинні нести відповідальність за використання належних URL-адрес.
Акостадінов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.