尝试通过应用启动默认浏览器到一个URL,但仅在输入的URL有效时,否则显示一条消息,指示该URL无效。
我该如何使用Swift检查有效性?
如果您的目标是验证应用程序是否能够打开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。
if let url = NSURL(string: urlString) {
。 - Vijay Singh Rana使用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。在许多情况下,用户在输入URL时不包括http://
或者https://
URL协议 - 例如,他们可能输入"www.google.com"
而不是"http://www.google.com"
。如果没有URL协议,UIApplication.shared.canOpenURL
将无法识别URL并返回false
。与UIApplication.shared.canOpenURL
相比,NSDataDetector
是一个相对宽容的工具(正如@AmitaiB在评论中提到的),它甚至可以检测没有http://
协议的URL。这样,我就能够在不必每次测试字符串时尝试添加协议的情况下检测URL。
附注 - SFSafariViewController
只能打开带有http://
/https://
协议的URL。因此,如果检测到的URL没有指定URL协议,并且您想要打开链接,则必须手动添加协议。
NSDataDetector
是一个相当宽容的检测工具。考虑以下内容:*isValidURL? true
*UIApplication.shared.canOpenURL? false
gskinner.com/products/spl
*iVU? T
*canOpen? F
https://google.com
*iVU? T
*canOpen? T
https:google.com
*iVU? T
*canOpen? T
www.cool.com.au
*iVU? T
*canOpen? F
http://www.cool.com.au
*iVU? T
*canOpen? T
http://www.cool.com.au/ersdfs
*iVU? T
*canOpen? T
http://www.cool.com.au/ersdfs?dfd=dfgd@s=1
*iVU? T
*canOpen? T
http://www.cool.com:81/index.html
*iVU? T
*canOpen? T
- AmitaiB"https://#view-?name=post&post.post_id=519&message.message_id=349".isValidUrl
这样的输入,它会返回true。 - mr5以下是接受答案的Swift 3版本:
func verifyUrl(urlString: String?) -> Bool {
if let urlString = urlString {
if let url = URL(string: urlString) {
return UIApplication.shared.canOpenURL(url)
}
}
return false
}
或者采用更具Swift特色的解决方案:
func verifyUrl(urlString: String?) -> Bool {
guard let urlString = urlString,
let url = URL(string: urlString) else {
return false
}
return UIApplication.shared.canOpenURL(url)
}
if let..
组合成单个检查,然后还可以将 if
翻转为 guard ... else { return false }
,以使 return false
成为失败状态,而 return UIApplication...
则是(可能的)成功状态。 - ReactiveRaven"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
}
string.characters.count
变成了 string.count
。 - Benjamin Schmidt我发现这个代码很简洁(用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.")
}
2020年,我被指派修复一个方法的漏洞,用于在字符串中下划线标记字符串链接。这里大多数答案都不能正常工作(尝试:aaa.com.bd 或 aaa.bd)这些链接应该是有效的。后来我发现了适用于此的正则表达式字符串。
所以基于那个正则表达式
"((?: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];
}
https://you.test.com/0003-example/
- iKK个人偏好是使用扩展来实现,因为我喜欢直接在字符串对象上调用方法。
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
或您的应用程序需要的任何内容)进行扩展。
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)
}
}
在某些情况下,只需检查URL是否符合RFC 1808即可。有几种方法可以做到这一点。以下是一个例子:
if let url = URL(string: urlString), url.host != nil {
// This is a correct url
}
Task <DF46917D-1A04-4E76-B54E-876423224DF7>.<72> finished with error - code: -1002
var url:NSURL = NSURL(string: "tel://000000000000")!
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
} else {
// Put your error handler code...
}