Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Swift中检查URL的有效性?_Url_Swift_Ios8 - Fatal编程技术网

如何在Swift中检查URL的有效性?

如何在Swift中检查URL的有效性?,url,swift,ios8,Url,Swift,Ios8,试图使应用程序启动URL的默认浏览器,但前提是输入的URL有效,否则会显示一条消息,说明URL无效 如何使用Swift检查有效性?您可以将NSURL类型(其构造函数返回可选类型)与结合使用来检查给定URL的有效性。换言之,利用Swift的一项关键功能NSURL: let stringWithPossibleURL: String = self.textField.text // Or another source of text if let validURL: NSURL = NSURL(s

试图使应用程序启动URL的默认浏览器,但前提是输入的URL有效,否则会显示一条消息,说明URL无效


如何使用Swift检查有效性?

您可以将
NSURL
类型(其构造函数返回可选类型)与结合使用来检查给定URL的有效性。换言之,利用Swift的一项关键功能
NSURL

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)
}

如果您的目标是验证应用程序是否可以打开URL,那么下面是您可以做的。虽然safari可以打开URL,但该网站可能不存在或已关闭

`// Swift 5
 func verifyUrl (urlString: String?) -> Bool {
    if let urlString = urlString {
        if let url = NSURL(string: urlString) {
            return UIApplication.shared.canOpenURL(url as URL)
        }
    }
    return false
}
`
作为旁注,这不会检查URL是否有效或完整。例如,通过“https://”的调用返回true

我发现这一个是干净的(用Swift):

var url:NSURL = NSURL(string: "tel://000000000000")!
if UIApplication.sharedApplication().canOpenURL(url) {
    UIApplication.sharedApplication().openURL(url)
} else {
     // Put your error handler code...
}
用法:

if canOpenURL("abc") {
    print("valid url.")
} else {
    print("invalid url.")
}
let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/"
if string.isValidURL {
    // TODO
}
===

对于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.")
}

对于接受答案的swift 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)
}

我个人的偏好是使用扩展来实现这一点,因为我喜欢直接在string对象上调用该方法

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
或您的应用程序所需的任何用例。

这不是一种正则表达式方法,但它是一种幼稚的方法,如果您想要一种简单且廉价的方法,它可以很好地确保有主机和扩展:

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
    }
}

仅当您希望在客户端快速检查,并且您有服务器逻辑,可以在保存数据之前进行更严格的检查时,才使用此选项。

使用“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
}
建议只使用此检查一次,然后重新使用

请注意,此功能的积分为。

请尝试以下操作:

func isValid(urlString: String) -> Bool
{
    if let urlComponents = URLComponents.init(string: urlString), urlComponents.host != nil, urlComponents.url != nil
    {
        return true
    }
    return false
}

这只是检查有效的URL组件,以及主机和URL组件是否为非空。此外,您可以将其添加到扩展名文件中,在某些情况下,检查url是否满足RFC1808就足够了。有几种方法可以做到这一点。一个例子:

if let url = URL(string: urlString), url.host != nil {
  // This is a correct url
}
这是因为如果url不符合RFC1808,则.host以及.path、.fragment和其他一些方法将返回nil

如果不检查,控制台日志中可能会有此类消息:

Task <DF46917D-1A04-4E76-B54E-876423224DF7>.<72> finished with error - code: -1002
任务。完成时出现错误-代码:-1002

对于swift 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
}

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
        }
    }
}
用法:

if canOpenURL("abc") {
    print("valid url.")
} else {
    print("invalid url.")
}
let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/"
if string.isValidURL {
    // TODO
}
使用
NSDataDetector
而不是
UIApplication.shared.canOpenURL
背后的推理:

我需要一种方法来检测用户是否提供了指向某个内容的URL的输入。在许多情况下,用户在键入的URL中不包括
http://
https://
URL方案,例如,不包括
”http://www.google.com“
他们会输入
“www.google.com”
。如果没有URL方案,
UIApplication.shared.canOpenURL
将无法识别URL,并返回
false
<与
UIApplication.shared.canOpenURL
相比,code>NSDataDetector是一个相当宽容的工具(如评论中提到的@AmitaiB),它甚至可以在没有
http://
方案的情况下检测URL。通过这种方式,我可以检测URL,而无需每次测试字符串时都尝试添加方案

旁注-
SFSafariViewController
只能使用
http://
/
https://
打开URL。因此,如果检测到的URL没有指定URL方案,并且您希望打开链接,则必须手动预先设置方案。

对于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
}

这是针对最新的Swift 4,基于Doug Amos答案(针对Swift 3)


这将为URL的有效性返回一个布尔值,如果传递了值为nil的可选URL,则返回nil

extension URL {

    var isValid: Bool {
        get {
            return UIApplication.shared.canOpenURL(self)
        }
    }

}

请注意,如果您计划使用Safari视图,则应通过验证测试
url.scheme==“http”| | url.scheme==“https”

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
  }
}
用法

必须处理各种计划:

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)
    }
}

使用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)
}

这个被接受的答案在我没有数据的错误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
}

希望这有帮助

2020年,我的任务是修复一个在字符串中为字符串链接加下划线的方法的错误。这里的大多数答案都不能正常工作(请尝试:aaa.com.bd或aaa.bd)。这些链接应该是有效的。然后我偶然发现了这个正则表达式字符串

参考:

基于这个正则表达式

"((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?"
“((?:http | https):/)(?:www\\)?[\\w\\d\\-\\+\\\.\\w{2,3}(\\.\\w{2}))(/(?Swift 5.1解决方案

extension String {
    func canOpenUrl() -> Bool {
        guard let url = URL(string: self), UIApplication.shared.canOpenURL(url) else { return false }
        let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
        let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx])
        return predicate.evaluate(with: self)
    }
}

发送一个NSURLRequest并检查返回值?使用该字符串形成一个NSURL并查看它是否为零?如果让urlString=urlString,url=NSURL(string:urlString),其中UIApplication.sharedApplication().canOpenURL(url){return true}在swift2.0
上测试时不起作用,如果让url=NSURL(string:urlString){
@VijaySinghRana这是一个有效的NSURL,此函数将不检查url是否存在。回答中指出:“如果您的目标是验证应用程序是否可以打开url,则此处是您可以执行的操作”。此方法打印此日志”-canOpenURL:url失败:“如果URL无效,则在调试器中。如何删除此项?谢谢。这很有帮助。这在google.com上似乎不起作用。它只需要@lwdthe1之类的内容。是的,正则表达式有一些漏洞。不过,提出的要点是解决方案的体系结构(通过扩展实现)。在你的应用程序中用你自己的正则表达式完全可以随意替换。或者如果你有更好的正则表达式-改进我的答案!:)同时它忠实于
"((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?"
extension String {
    var validURL: Bool {
        get {
            let regEx = "((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?"
            let predicate = NSPredicate(format: "SELF MATCHES %@", argumentArray: [regEx])
            return predicate.evaluate(with: self)
        }
    }
}
- (BOOL)stringIsValidURL:(NSString *)string
{
    NSString *regEx = @"((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@" argumentArray:@[regEx]];
    return [predicate evaluateWithObject:string];
}
extension String {
    func canOpenUrl() -> Bool {
        guard let url = URL(string: self), UIApplication.shared.canOpenURL(url) else { return false }
        let regEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
        let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[regEx])
        return predicate.evaluate(with: self)
    }
}