Как проверить правильность URL-адреса в Swift?
Попытка заставить приложение запустить браузер по умолчанию для URL-адреса, но только если введенный URL-адрес действителен, в противном случае отображается сообщение о том, что URL-адрес недействителен.
Как я могу проверить правильность использования Swift?
Ответы
Ответ 1
Если ваша цель - проверить, может ли ваше приложение открыть URL-адрес, вот что вы можете сделать. Хотя сафари может открыть Url, веб-сайт может не существовать или он может быть недоступен.
func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = NSURL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.sharedApplication().canOpenURL(url)
}
}
return false
}
Ответ 2
Swift 4 элегантное решение с использованием NSDataDetector
:
extension String {
var isValidURL: Bool {
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
if let match = detector.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count)) {
// it is a link, if the match covers the whole string
return match.range.length == self.utf16.count
} else {
return false
}
}
}
Использование:
let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/"
if string.isValidURL {
// TODO
}
NSDataDetector
использования NSDataDetector
вместо UIApplication.shared.canOpenURL
:
Мне нужен был метод, который бы определял, предоставил ли пользователь ввод, который является URL-адресом для чего-либо. Во многих случаях пользователи не включают схему URL http://
или https://
в URL, который они вводят - например, вместо "http://www.google.com"
они вводят "www.google.com"
. Без схемы URL UIApplication.shared.canOpenURL
не сможет распознать URL и вернет false
. NSDataDetector
, по сравнению с '', довольно простительный инструмент (как упомянуто в комментариях @AmitaiB) - и он может обнаруживать даже URL без схемы http://
. Таким образом, я могу обнаружить URL, не пытаясь добавлять схему каждый раз при тестировании строки.
Sidenote - SFSafariViewController
может открывать только URL с http://
/https://
. Таким образом, если для обнаруженного URL-адреса не указана схема URL-адреса, и вы хотите открыть ссылку, вам придется предварительно добавить схему вручную.
Ответ 3
Для быстрой версии 3 принятого ответа:
func verifyUrl(urlString: String?) -> Bool {
if let urlString = urlString {
if let url = URL(string: urlString) {
return UIApplication.shared.canOpenURL(url)
}
}
return false
}
Или для более быстрого решения:
func verifyUrl(urlString: String?) -> Bool {
guard let urlString = urlString,
let url = URL(string: urlString) else {
return false
}
return UIApplication.shared.canOpenURL(url)
}
Ответ 4
Я нашел этот чистый (In Swift):
func canOpenURL(string: String?) -> Bool {
guard let urlString = string else {return false}
guard let url = NSURL(string: urlString) else {return false}
if !UIApplication.sharedApplication().canOpenURL(url) {return false}
//
let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx])
return predicate.evaluateWithObject(string)
}
Использование:
if canOpenURL("abc") {
print("valid url.")
} else {
print("invalid url.")
}
===
для Swift 4.1:
func canOpenURL(_ string: String?) -> Bool {
guard let urlString = string,
let url = URL(string: urlString)
else { return false }
if !UIApplication.shared.canOpenURL(url) { return false }
let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx])
return predicate.evaluate(with: string)
}
// Usage
if canOpenURL("abc") {
print("valid url.")
} else {
print("invalid url.") // This line executes
}
if canOpenURL("https://www.google.com") {
print("valid url.") // This line executes
} else {
print("invalid url.")
}
Ответ 5
Использование "canOpenUrl" было слишком дорого для моего использования, я нашел этот подход более быстрым
func isStringLink(string: String) -> Bool {
let types: NSTextCheckingResult.CheckingType = [.link]
let detector = try? NSDataDetector(types: types.rawValue)
guard (detector != nil && string.characters.count > 0) else { return false }
if detector!.numberOfMatches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, string.characters.count)) > 0 {
return true
}
return false
}
Ответ 6
var url:NSURL = NSURL(string: "tel://000000000000")!
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
} else {
// Put your error handler code...
}
Ответ 7
Мое личное предпочтение - приблизиться к этому с расширением, потому что мне нравится называть метод непосредственно на строковый объект.
extension String {
private func matches(pattern: String) -> Bool {
let regex = try! NSRegularExpression(
pattern: pattern,
options: [.caseInsensitive])
return regex.firstMatch(
in: self,
options: [],
range: NSRange(location: 0, length: utf16.count)) != nil
}
func isValidURL() -> Bool {
guard let url = URL(string: self) else { return false }
if !UIApplication.shared.canOpenURL(url) {
return false
}
let urlPattern = "^(http|https|ftp)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.&%\\$\\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+\\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\?\\'\\\\\\+&%\\$#\\=~_\\-]+))*$"
return self.matches(pattern: urlPattern)
}
}
Таким образом, он также расширяется с другими прецедентами, такими как isValidEmail
, isValidName
или независимо от того, что требуется вашему приложению.
Ответ 8
Вы можете использовать тип NSURL
(конструктор которого возвращает необязательный тип) в сочетании с оператором if-let
для проверки правильности заданного URL-адреса. Другими словами, используйте NSURL
failable initializer, ключевую особенность Swift:
let stringWithPossibleURL: String = self.textField.text // Or another source of text
if let validURL: NSURL = NSURL(string: stringWithPossibleURL) {
// Successfully constructed an NSURL; open it
UIApplication.sharedApplication().openURL(validURL)
} else {
// Initialization failed; alert the user
let controller: UIAlertController = UIAlertController(title: "Invalid URL", message: "Please try again.", preferredStyle: .Alert)
controller.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(controller, animated: true, completion: nil)
}
Ответ 9
Для версии Swift 4
static func isValidUrl (urlString: String?) -> Bool {
if let urlString = urlString {
if let url = URL(string: urlString) {
return UIApplication.shared.canOpenURL(url)
}
}
return false
}
Ответ 10
Это вернет логическое значение для валидности URL или nil, если передан необязательный URL со значением nil.
extension URL {
var isValid: Bool {
get {
return UIApplication.shared.canOpenURL(self)
}
}
}
Обратите внимание, что если вы планируете использовать представление Safari, вам следует протестировать url.scheme == "http" || url.scheme == "https"
url.scheme == "http" || url.scheme == "https"
.
Ответ 11
Swift 4.2 Элегантная конструкция URL с проверкой
import Foundation
import UIKit
extension URL {
init?(withCheck string: String?) {
let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
guard
let urlString = string,
let url = URL(string: urlString),
NSPredicate(format: "SELF MATCHES %@", argumentArray: [regEx]).evaluate(with: urlString),
UIApplication.shared.canOpenURL(url)
else {
return nil
}
self = url
}
}
использование
var imageUrl: URL? {
if let url = URL(withCheck: imageString) {
return url
}
if let url = URL(withCheck: image2String) {
return url
}
return nil
}
Ответ 12
Это не подход с регулярным выражением, но он наивный, который хорошо работает, чтобы убедиться, что есть хост и расширение, если вы хотите простой и недорогой подход:
extension String {
var isValidUrlNaive: Bool {
var domain = self
guard domain.count > 2 else {return false}
guard domain.trim().split(" ").count == 1 else {return false}
if self.containsString("?") {
var parts = self.splitWithMax("?", maxSplit: 1)
domain = parts[0]
}
return domain.split(".").count > 1
}
}
Используйте это, только если вам нужен быстрый способ проверки на стороне клиента, и у вас есть логика сервера, которая проведет более строгую проверку перед сохранением данных.
Ответ 13
extension String {
func isStringLink() -> Bool {
let types: NSTextCheckingResult.CheckingType = [.link]
let detector = try? NSDataDetector(types: types.rawValue)
guard (detector != nil && self.characters.count > 0) else { return false }
if detector!.numberOfMatches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count)) > 0 {
return true
}
return false
}
}
//Usage
let testURL: String = "http://www.google.com"
if testURL.isStringLink() {
//Valid!
} else {
//Not valid.
}
Он рекомендовал использовать эту проверку только один раз, а затем повторно использовать.
PS Кредиты для Shachar для этой функции.
Ответ 14
В некоторых случаях этого может быть достаточно, чтобы проверить, что URL-адрес удовлетворяет RFC 1808. Существует несколько способов сделать это. Один пример:
if let url = URL(string: urlString), url.host != nil {
// This is a correct url
}
Это связано с тем, что.host, а также.path,.fragment и несколько других методов будут возвращать нуль, если URL-адрес не соответствует RFC 1808.
Если вы не проверите, у вас могут быть такие сообщения в журнале консоли:
Task <DF46917D-1A04-4E76-B54E-876423224DF7>.<72> finished with error - code: -1002
Ответ 15
Попробуй это:
func isValid(urlString: String) -> Bool
{
if let urlComponents = URLComponents.init(string: urlString), urlComponents.host != nil, urlComponents.url != nil
{
return true
}
return false
}
Это просто проверяет действительные компоненты URL, и если компоненты хоста и URL-адреса не ноль. Кроме того, вы можете просто добавить это в файл расширений
Ответ 16
Для быстрого 4 вы можете использовать:
class func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = URL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.shared.canOpenURL(url)
}
}
return false
}
Ответ 17
Это для последней версии Swift 4, основанной на ответе Дуга Амоса (для быстрого 3)
public static func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = NSURL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.shared.canOpenURL(url as URL)
}
}
return false
}
Ответ 18
Гелию приходится иметь дело с различными схемами:
struct UrlHelpers {
// Prepends 'http://' if scheme isn't 'https?://' unless "file://"
static func ensureScheme(_ urlString: String) -> String {
if !(urlString.lowercased().hasPrefix("http://") || urlString.lowercased().hasPrefix("https://")) {
return urlString.hasPrefix("file://") ? urlString : "http://" + urlString
} else {
return urlString
}
}
// https://mathiasbynens.be/demo/url-regex
static func isValid(urlString: String) -> Bool {
// swiftlint:disable:next force_try
if urlString.lowercased().hasPrefix("file:"), let url = URL.init(string: urlString) {
return FileManager.default.fileExists(atPath:url.path)
}
let regex = try! NSRegularExpression(pattern: "^(https?://)[^\\s/$.?#].[^\\s]*$")
return (regex.firstMatch(in: urlString, range: urlString.nsrange) != nil)
}
}
Ответ 19
Версия, которая работает с Swift 4.2 и имеет надежное сопоставление с образцом URL...
func matches(pattern: String) -> Bool
{
do
{
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: utf16.count)) != nil
}
catch
{
return false
}
}
func isValidURL() -> Bool
{
guard let url = URL(string: self) else { return false }
if !UIApplication.shared.canOpenURL(url) { return false }
let urlPattern = "(http|ftp|https):\\/\\/([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?"
return self.matches(pattern: urlPattern)
}
Ответ 20
Этот принятый ответ не работает в моем случае с неправильным URL без данных https://debug-cdn.checkit4team.com/5/image/Y29tbW9uL2RlZmF1bHRfYXZhdGFyLnBuZw==
Поэтому я пишу расширение для решения
extension String {
var verifyUrl: Bool {
get {
let url = URL(string: self)
if url == nil || NSData(contentsOf: url!) == nil {
return false
} else {
return true
}
}
}
}
Используйте это:
if string. verifyUrl {
// do something
}
Надеюсь, это поможет!