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

时间:2015-01-21 23:57:44

标签: url swift ios8

尝试让应用启动默认浏览器到网址,但前提是输入的网址有效,否则会显示一条消息,说明网址无效。

如何使用Swift检查有效性?

22 个答案:

答案 0 :(得分:77)

如果您的目标是验证您的应用程序是否可以打开网址,那么您可以执行此操作。虽然safari可以打开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
}

答案 1 :(得分:23)

使用NSDataDetector

Swift 4 优雅的解决方案

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代替UIApplication.shared.canOpenURL 的推理:

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

旁注 - SFSafariViewController只能打开http:// / https://的网址。因此,如果检测到的URL没有指定URL方案,并且您想要打开该链接,则必须手动添加该方案。

答案 2 :(得分:21)

对于接受答案的快速3版本:

func verifyUrl(urlString: String?) -> Bool {
    if let urlString = urlString {
        if let url = URL(string: urlString) {
            return UIApplication.shared.canOpenURL(url)
        }
    }
    return false
}

或者更多Swifty解决方案:

func verifyUrl(urlString: String?) -> Bool {
    guard let urlString = urlString,
          let url = URL(string: urlString) else { 
        return false 
    }

    return UIApplication.shared.canOpenURL(url)
}

答案 3 :(得分:13)

我发现这个很干净(在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.")
}

答案 4 :(得分:13)

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

答案 5 :(得分:5)

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

答案 6 :(得分:4)

我个人的偏好是使用扩展来解决这个问题,因为我喜欢直接在字符串对象上调用该方法。

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

通过这种方式,它还可以使用其他用例进行扩展,例如isValidEmailisValidName或您的应用程序所需的任何用例。

答案 7 :(得分:3)

2020年,我的任务是修复在字符串中加下划线的方法的错误。此处的大多数答案均无法正常使用(尝试:aaa.com.bd或aaa.bd)。这些链接应有效。然后我偶然发现了正则表达式字符串。

参考:https://urlregex.com/

因此基于该正则表达式

"((?:http|https)://)?(?:www\\.)?[\\w\\d\\-_]+\\.\\w{2,3}(\\.\\w{2})?(/(?<=/)(?:[\\w\\d\\-./_]+)?)?"

我们可以编写一个函数。

SWIFT 5.x

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

OBJECTIVE-C (不管您想写什么,都可以写,不管是不是)。

- (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];
}

答案 8 :(得分:2)

您可以使用NSURL类型(其构造函数返回可选类型)与if-let statement结合使用来检查给定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 :(得分:2)

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
}

答案 10 :(得分:2)

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

extension URL {

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

}

请注意,如果您打算使用Safari视图,则应测试url.scheme == "http" || url.scheme == "https"

答案 11 :(得分:2)

对于Swift 4版本

library(shiny)

ui <- fluidPage(
  mainPanel(
         textOutput("ptext")
      ))

server <- function(input, output) {
   output$ptext <- renderText("creating a dataframe")
   df <- matrix(rnorm(10000),nrow = 10) # a large dataset
   output$ptext <- renderText("dataframe created !!")
   }

shinyApp(ui = ui, server = server)

答案 12 :(得分:1)

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

答案 13 :(得分:1)

在某些情况下,检查网址是否满足RFC 1808就足够了。有几种方法可以做到这一点。一个例子:

if let url = URL(string: urlString), url.host != nil {
  // This is a correct url
}

这是因为.host,以及.path,.fragment和其他一些方法如果url不符合RFC 1808,则会返回nil。

如果您不检查,您可能在控制台日志中有这种消息:

Task <DF46917D-1A04-4E76-B54E-876423224DF7>.<72> finished with error - code: -1002

答案 14 :(得分:1)

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

建议只使用此检查一次,然后重复使用。

<子> P.S。对此功能的信用为Shachar

答案 15 :(得分:1)

这不是一种正则表达式方法,但它是一个天真的方法,如果你想要一个简单而廉价的方法,确保有一个主机和一个扩展,效果很好:

import matplotlib.pyplot as plt
df.plot.bar()
df.plot()
plt.show(block=True)

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

答案 16 :(得分:0)

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

答案 17 :(得分:0)

这是针对最新的 Swift 4 ,基于 Doug Amos 答案(适用于swift 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 :(得分:0)

试试这个:

var linkedInUrl = `https://api.linkedin.com/v1/people/~:(id,email-address)?format=json`;
  var headers = {
    'Authorization': `Bearer ${accessToken}`,
    'Access-Control-Allow-Methods':'GET,PUT,PATCH,POST,DELETE',
    'Access-Control-Allow-Origin':'*',
    'Access-Control-Request-Headers':'Origin, X-Requested-With, Content-Type, Accept',
    'Content-Type':'application/x-www-form-urlencoded'
  };

  return (dispatch) => {
    axios.get(linkedInUrl, {headers}).then(({data}) => {
        console.log(data);
    }, (error) => {
        console.log(error);
    });
  }

这只是检查有效的URL组件以及主机和网址组件是否为零。此外,您只需将其添加到扩展文件

即可

答案 19 :(得分:0)

Helium必须处理各种方案:

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

答案 20 :(得分:0)

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

答案 21 :(得分:0)

在我的情况下,如果没有数据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
}

希望获得帮助!