programing

스위프트에서 URL 유효성을 확인하는 방법은?

padding 2023. 9. 15. 20:48
반응형

스위프트에서 URL 유효성을 확인하는 방법은?

앱이 URL에 대한 기본 브라우저를 실행하려고 하지만 입력한 URL이 유효한 경우에만 해당 URL이 유효하지 않다는 메시지가 표시됩니다.

스위프트를 이용하여 유효성을 확인하려면 어떻게 해야 합니까?

응용프로그램이 URL을 열 수 있는지 확인하는 것이 목표라면 다음과 같이 수행할 수 있습니다.사파리는 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 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
}

다음 대신 사용할 수 있는 추론:

사용자가 어떤 것에 URL인 입력을 제공했는지 감지할 수 있는 방법이 필요했습니다.많은 경우 사용자는 다음을 포함하지 않습니다.http://도 아니다https://를 들어,를어는신킴 URL의 "http://www.google.com"그들은 타이핑을 할 것입니다."www.google.com"스킴 . URL ,UIApplication.shared.canOpenURL URL을 합니다.false.NSDataDetector와에 UIApplication.shared.canOpenURL댓글에 된 @같이)도구 - 이 는 , ( @ ) - URL 하지 할 도 은 한 된 에서 할 도 하지 은 http:// 하면 할 때 할 수 .이렇게 하면 문자열을 테스트할 때 매번 스킴을 추가할 필요 없이 URL을 검출할 수 있습니다.

- -SFSafariViewController를하여 URL열수다만다 URL만 열 수 있습니다.http:///https://지정되어 을 수동으로. 따라서 탐지된 URL에 URL 스킴이 지정되어 있지 않고 링크를 열려면 스킴을 수동으로 추가해야 합니다.

승인된 답변의 신속한 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)
}

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

깨끗한 것을 발견했습니다 (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.")
}

===

스위프트 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 ).이러한 링크는 유효해야 합니다.그리고 나서 나는 이것을 위해 정규분포를 우연히 발견했습니다.

참조: 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)
        }
    }
}

목표-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];
}

저의 개인적인 선호는 이것을 확장으로 접근하는 것입니다. 왜냐하면 저는 메소드를 문자열 객체에 직접 호출하는 것을 좋아하기 때문입니다.

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\\.&amp;%\\$\\-]+)*@)*((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\\.\\,\\?\\'\\\\\\+&amp;%\\$#\\=~_\\-]+))*$"
        return self.matches(pattern: urlPattern)
    }
}

이러한 방식으로 다음과 같은 다른 사용 사례로도 확장할 수 있습니다.isValidEmail,isValidName필요한 것이 무엇이든 간에.

스위프트 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)
    }
}
var url:NSURL = NSURL(string: "tel://000000000000")!
if UIApplication.sharedApplication().canOpenURL(url) {
    UIApplication.sharedApplication().openURL(url)
} else {
     // Put your error handler code...
}

경우에 따라서는 URL이 RFC 1808을 만족하는지 확인하기에 충분할 수 있습니다.이렇게 하는 방법에는 여러 가지가 있습니다.한 가지 예:

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

이는 .host, .path, .fragment 및 다른 몇 가지 메서드는 url이 RFC 1808과 호환되지 않으면 0으로 반환되기 때문입니다.

확인하지 않으면 콘솔 로그에 다음과 같은 메시지가 표시될 수 있습니다.

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

스위프트 4 버전의 경우

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

사용할 수 있습니다.NSURL지정된 URL의 유효성을 확인하기 위해 type(생성자가 선택적 유형을 반환하는)을 문과 결합합니다.다시 말해, 다음을 활용합니다.NSURL Swift의 주요 기능인 failable initializer:

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

이 검사는 한 번만 사용하고 다시 사용하는 것이 좋습니다.

추신: 이 기능에 대해 Shachar에게 공을 돌립니다.

이렇게 하면 URL의 유효성에 대한 부울이 반환되고 값이 0인 선택 URL이 전달되면 0이 반환됩니다.

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

사용.

var imageUrl: URL? {
    if let url = URL(withCheck: imageString) {
        return url
    }
    if let url = URL(withCheck: image2String) {
        return url
    }
    return nil
}

이것은 regex 접근 방식이 아니지만, 단순하고 저렴한 접근 방식을 원하는 경우 호스트와 확장 기능이 있는지 확인하는 데 효과적인 순진한 접근 방식입니다.

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

클라이언트 측에서 빠르게 확인할 수 있는 방법을 원하며 데이터를 저장하기 전에 보다 엄격한 검사를 수행하는 서버 로직이 있는 경우에만 이 방법을 사용합니다.

시도해 보기:

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

이렇게 하면 유효한 URL 구성 요소와 호스트 및 URL 구성 요소가 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
}

다양한 계획을 처리해야 하는 헬륨:

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

이것은 최신 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
}

대부분의 답변은 제 문제를 해결할 수 없기 때문에 제가 어떻게 해결했는지 여기에 글을 올립니다.

static func isValidDomain(domain: String?) -> Bool {
    guard let domain = domain else {
        return false
    }
    // Modified version of https://stackoverflow.com/a/49072718/2304737
    let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
    let domainWithScheme = "https://\(domain)"
    if let url = URL(string: domainWithScheme),
       let match = detector.firstMatch(in: domainWithScheme, options: [], range: NSRange(location: 0, length: domainWithScheme.utf16.count)) {
        // it is a link, if the match covers the whole string
        return match.range.length == domainWithScheme.utf16.count && url.host != nil
    } else {
        return false
    }
}

밀란 노사시의 답변에 부족한 점은 이와 같은 특정한 의견을 다루지 않는다는 것입니다.

https://#view-?name=post&post.post_id=519&message.message_id=349

그래서 저는 그냥 덧붙입니다.host존재 여부를 확인하고 "URL"을 해제합니다.

//Add in "extension String"
func verifyUrl()  -> Bool {
    var newString = self
    let index = self.index(self.startIndex, offsetBy: 4)
    let mySubstring = self.prefix(upTo: index)
    if mySubstring == "www." {
        newString = "https://" + newString
    }
    if let url = NSURL(string: newString) {
        return UIApplication.shared.canOpenURL(url as URL)
    }
    return false
}
extension String {
  var isValidUrl: Bool {
    if let url = NSURL(string: self) {
      return UIApplication.shared.canOpenURL(url as URL)
    }
    return false
  }
}

용도:

let test1 = "abc"
let isValidUrl = test1.isValidUrl

// Result of isValidUrl will be False


let test1 = "https://www.google.com/"
let isValidUrl = test1.isValidUrl

// Result of isValidUrl will be True

이 승인된 답변은 데이터가 없는 잘못된 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
}

도움이 되길 바랍니다!

언급URL : https://stackoverflow.com/questions/28079123/how-to-check-validity-of-url-in-swift

반응형