在没有方案的情况下验证 URL

Validate URL without scheme

Swift5,Xcode10,iOS12

我的代码使用 UIApplication.shared.canOpenURL 来验证 URL,不幸的是,没有例如"http://".

示例:

print(UIApplication.shared.canOpenURL(URL(string: "whosebug.com")!)) //false
print(UIApplication.shared.canOpenURL(URL(string: "http://whosebug.com")!)) //true
print(UIApplication.shared.canOpenURL(URL(string: "129.0.0.1")!)) //false
print(UIApplication.shared.canOpenURL(URL(string: "ftp://129.0.0.1")!)) //true

我知道 schemes (iOS9+) 的变化,我知道如果字符串没有开始,我可以添加像 "http://" 这样的前缀已经有了它,然后检查这个新字符串,但我仍然想知道:

问题: 我如何添加 "there's no scheme" 方案,这样有效的 URL 也像 "whosebug.com" return true (这甚至可能吗?)?

这是我使用的方法

extension String {

    /// Return first available URL in the string else nil
    func checkForURL() -> NSRange? {
        guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
            return nil
        }
        let matches = detector.matches(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count))

        for match in matches {
            guard Range(match.range, in: self) != nil else { continue }
            return match.range
        }
        return nil
    }

    func getURLIfPresent() -> String? {
        guard let range = self.checkForURL() else{
            return nil
        }
        guard let stringRange = Range(range,in:self) else {
            return nil
        }
        return String(self[stringRange])
    }
}

显然,方法名和代码中的注释不够冗长,所以这里解释一下。

已使用 NSDataDetector and provided it the type - NSTextCheckingResult.CheckingType.link 检查 link 秒。

这遍历提供的字符串和 return 的 URL 类型的所有匹配项。

这将检查您提供的字符串中的 link,如果有的话,否则 returns nil。

方法 getURLIfPresent return 该字符串的 URL 部分。

这里有几个例子

print("http://whosebug.com".getURLIfPresent())
print("whosebug.com".getURLIfPresent())
print("ftp://127.0.0.1".getURLIfPresent())
print("www.google.com".getURLIfPresent())
print("127.0.0.1".getURLIfPresent())
print("127".getURLIfPresent())
print("hello".getURLIfPresent())

Output

Optional("http://whosebug.com")
Optional("whosebug.com")
Optional("ftp://127.0.0.1")
Optional("www.google.com")
nil
nil
nil

但是,对于“127.0.0.1”,这 return 并不成立。所以我不认为它会实现你的事业。 就您而言,采用正则表达式的方式似乎更好。如果您遇到更多需要被视为 URL.

的模式,您可以添加更多条件

无法向 URL 添加有效方案,因为没有人知道哪个前缀将添加到哪个 URL。您可以在 regex.

的帮助下验证 URL

我搜索并修改了正则表达式。

extension String { 
    func isValidUrl() -> Bool { 
        let regex = "((http|https|ftp)://)?((\w)*|([0-9]*)|([-|_])*)+([\.|/]((\w)*|([0-9]*)|([-|_])*))+" 
        let predicate = NSPredicate(format: "SELF MATCHES %@", regex) 
        return predicate.evaluate(with: self) 
    } 
}

我用下面的网址测试了它:

print("http://whosebug.com".isValidUrl()) 
print("whosebug.com".isValidUrl()) 
print("ftp://127.0.0.1".isValidUrl()) 
print("www.google.com".isValidUrl()) 
print("127.0.0.1".isValidUrl()) 
print("127".isValidUrl()) 
print("hello".isValidUrl())

Output

true 
true 
true 
true 
true 
false 
false

注意: 100% 正则表达式无法验证 emailurl