iPhoneでURLを検証する方法


90

私が開発しているiPhoneアプリでは、URLを入力できる設定があります。フォームと機能により、このURLはオンラインだけでなくオフラインでも検証する必要があります。

これまでのところ、URLを検証する方法を見つけることができなかったので、問題は次のとおりです。

iPhone(Objective-C)でのURL入力をオンラインだけでなくオフラインでも検証するにはどうすればよいですか?


彼の答えへのコメントを読んでください、検証は正しく機能しません。
Thizzer 2013年

回答:


98

この投稿のおかげで、RegexKitの使用を回避できます。これが私の解決策です(iOS> 3.0でのiPhone開発に機能します):

- (BOOL) validateUrl: (NSString *) candidate {
    NSString *urlRegEx =
    @"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
    NSPredicate *urlTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", urlRegEx]; 
    return [urlTest evaluateWithObject:candidate];
}

あなたがSwiftにチェックインしたい場合は、以下の私の解決策:

 func isValidUrl(url: String) -> Bool {
        let urlRegEx = "^(https?://)?(www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6}(/[-\\w@\\+\\.~#\\?&/=%]*)?$"
        let urlTest = NSPredicate(format:"SELF MATCHES %@", urlRegEx)
        let result = urlTest.evaluate(with: url)
        return result
    }

7
これが唯一のタイプのURLのために働く「webr.ly」などのパラメータを持つURLの仕事をしませんyoutube.com/watch?v=mqgExtdNMBk
便利な

5
((http|https)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+".http://またはhttps://を最適にする必要があります。
Yeung、

google.com、www.google.com、および//www.google.comでも機能しない
Revinder

次のURLは私の場合機能しません。 money.cnn.com/2015/10/19/technology/apple-app-store/...
DJtiwari

@DJtiwari +1はい、それは機能していませんそれに対する修正は見つかりましたか?
Hamza MHIRA、2015

239

代わりに単に依存しないのはなぜFoundation.frameworkですか?

それは仕事をし、必要としませんRegexKit

NSURL *candidateURL = [NSURL URLWithString:candidate];
// WARNING > "test" is an URL according to RFCs, being just a path
// so you still should check scheme and all other NSURL attributes you need
if (candidateURL && candidateURL.scheme && candidateURL.host) {
  // candidate is a well-formed url with:
  //  - a scheme (like http://)
  //  - a host (like stackoverflow.com)
}

Appleのドキュメントによると:

URLWithString:提供された文字列で初期化されたNSURLオブジェクトを作成して返します。

+ (id)URLWithString:(NSString *)URLString

パラメーター

URLString:NSURLオブジェクトの初期化に使用する文字列。RFC 2396に準拠する必要があります。このメソッドは、RFC 1738および1808に従ってURLStringを解析します。

戻り値

URLStringで初期化されたNSURLオブジェクト。文字列が不正な形式の場合、nilを返します。


1
私はここで他のいくつかに同意します。これは、正規表現をいじるはるかに優れたソリューションです。これは正しくチェックされた答えになるはずです。
ディエゴバロス

1
@MrThys-これがキャッチしない不正なURLの例を提供できる可能性はありますか?知ることは素晴らしいことです..これまでのところ優れた解決策のようです。
Don Vaughn

7
@DonamiteIsTnt URL http://www.aol.comhttp://www.nytimes.comはこのテストに合格しています。
アーロンブラジャー

1
コードは不正なURLをチェックしません。例:<code> afasd </ code >、URLは引き続きテストに合格します
デニル

39
ドキュメントが間違っています。いくつかのテストをNSURL記述します— @ "#@#@ $ ##%$#$#"または@ "tp:/ fdfdfsfdsf"の文字列を渡してもnilは返されません。そのため、このメソッドは有効なHTTP URLなどをチェックするのには役に立たないでしょう。
Tony Arnold、

32

独自の正規表現を作成する代わりに、Appleに依存します。文字列内のリンクの存在をテストするためにNSStringを使用するカテゴリを使用NSDataDetectorしています。で見つかったリンクの範囲がNSDataDetector文字列全体の長さに等しい場合、それは有効なURLです。

- (BOOL)isValidURL {
    NSUInteger length = [self length];
    // Empty strings should return NO
    if (length > 0) {
        NSError *error = nil;
        NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
        if (dataDetector && !error) {
            NSRange range = NSMakeRange(0, length);
            NSRange notFoundRange = (NSRange){NSNotFound, 0};
            NSRange linkRange = [dataDetector rangeOfFirstMatchInString:self options:0 range:range];
            if (!NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange)) {
                return YES;
            }
        }
        else {
            NSLog(@"Could not create link data detector: %@ %@", [error localizedDescription], [error userInfo]);
        }
    }
    return NO;
}

非常に賢い。実際のエンジニアリング。{ご存じのように、文字列「<null>」を送信するとクラッシュするという奇妙な問題が発生しました。それを理解することはできませんでした。}
Fattie

ああ-それは息子の「<null>」でした、アップルはNSNullとして便利に供給します!:O
Fattie 2014年

私は要点を作成し、ここでこの切り詰めたテストケースを追加し始めました。さらに追加するには無料で入力してください。gist.github.com/b35097bad451c59e23b1.git
Yevhen Dubinin

26

Swiftでの私のソリューション:

func validateUrl (stringURL : NSString) -> Bool {

    var urlRegEx = "((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+"
    let predicate = NSPredicate(format:"SELF MATCHES %@", argumentArray:[urlRegEx])
    var urlTest = NSPredicate.predicateWithSubstitutionVariables(predicate)

    return predicate.evaluateWithObject(stringURL)
}

テスト用:

var boolean1 = validateUrl("http.s://www.gmail.com")
var boolean2 = validateUrl("https:.//gmailcom")
var boolean3 = validateUrl("https://gmail.me.")
var boolean4 = validateUrl("https://www.gmail.me.com.com.com.com")
var boolean6 = validateUrl("http:/./ww-w.wowone.com")
var boolean7 = validateUrl("http://.www.wowone")
var boolean8 = validateUrl("http://www.wow-one.com")
var boolean9 = validateUrl("http://www.wow_one.com")
var boolean10 = validateUrl("http://.")
var boolean11 = validateUrl("http://")
var boolean12 = validateUrl("http://k")

結果:

false
false
false
true
false
false
true
true
false
false
false

10

これを使って-

NSString *urlRegEx = @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&amp;=]*)?";

1
私は単にasp.net正規表現バリデーターのためにそれをコピーしました;)
Vaibhav Saran

完璧、唯一の問題はそれが認識しないことですwww.google.com/+gplusname
MuhammadBassio

5

RegexKitを使用して問題を解決し、URLを検証するための簡単な正規表現を作成しました。

NSString *regexString = @"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSString *subjectString = brandLink.text;
NSString *matchedString = [subjectString stringByMatching:regexString];

次に、matchedStringがsubjectStringと等しいかどうかを確認し、それがtrueの場合、URLは有効です:)

正規表現が間違っている場合は修正してください;)


私は間違っているかもしれませんが、正規表現はクエリ文字列や名前付きアンカーでURLを検証しないと思います。
hpique 2010年

(http | https)://を((http | https)://)*に置き換えることでプレフィックス部分をオプションにすることができますが、これにより非常に幅広いURLが許可されます
Thizzer

4

奇妙なことに、私は本当に非常に簡単だった、ここで解決策を見つけるが、それでも処理するためのいい仕事をしてくれませんでしたhttp/ httpsリンクを。

これは完璧な解決策ではありませんが、以下の場合はうまくいきました。要約すると、正規表現はURLがhttp://またはhttps://で始まるかどうかをテストし、少なくとも1文字をチェックし、次にドットをチェックしてから、再び少なくとも1文字をチェックします。スペースは使用できません。

+ (BOOL)validateLink:(NSString *)link
{
    NSString *regex = @"(?i)(http|https)(:\\/\\/)([^ .]+)(\\.)([^ \n]+)";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    return [predicate evaluateWithObject:link];
}

次のURLに対して有効なテスト:

@"HTTP://FOO.COM",
@"HTTPS://FOO.COM",
@"http://foo.com/blah_blah",
@"http://foo.com/blah_blah/",
@"http://foo.com/blah_blah_(wikipedia)",
@"http://foo.com/blah_blah_(wikipedia)_(again)",
@"http://www.example.com/wpstyle/?p=364",
@"https://www.example.com/foo/?bar=baz&inga=42&quux",
@"http://✪df.ws/123",
@"http://userid:password@example.com:8080",
@"http://userid:password@example.com:8080/",
@"http://userid@example.com",
@"http://userid@example.com/",
@"http://userid@example.com:8080",
@"http://userid@example.com:8080/",
@"http://userid:password@example.com",
@"http://userid:password@example.com/",
@"http://142.42.1.1/",
@"http://142.42.1.1:8080/",
@"http://➡.ws/䨹",
@"http://⌘.ws",
@"http://⌘.ws/",
@"http://foo.com/blah_(wikipedia)#cite-",
@"http://foo.com/blah_(wikipedia)_blah#cite-",
@"http://foo.com/unicode_(✪)_in_parens",
@"http://foo.com/(something)?after=parens",
@"http://☺.damowmow.com/",
@"http://code.google.com/events/#&product=browser",
@"http://j.mp",
@"http://foo.bar/?q=Test%20URL-encoded%20stuff",
@"http://مثال.إختبار",
@"http://例子.测试",
@"http://उदाहरण.परीक्षा",
@"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
@"http://1337.net",
@"http://a.b-c.de",
@"http://223.255.255.254"

次のURLに対して無効とテストされました:

@"",
@"foo",
@"ftp://foo.com",
@"ftp://foo.com",
@"http://..",
@"http://..",
@"http://../",
@"//",
@"///",
@"http://##/",
@"http://.www.foo.bar./",
@"rdar://1234",
@"http://foo.bar?q=Spaces should be encoded",
@"http:// shouldfail.com",
@":// should fail"

URLのソース:https : //mathiasbynens.be/demo/url-regex


3

あなたがしたくない場合httphttpsまたはこれを使用できますwww

NSString *urlRegEx = @"^(http(s)?://)?((www)?\.)?[\w]+\.[\w]+";

- (void) testUrl:(NSString *)urlString{
    NSLog(@"%@: %@", ([self isValidUrl:urlString] ? @"VALID" : @"INVALID"), urlString);
}

- (void)doTestUrls{
    [self testUrl:@"google"];
    [self testUrl:@"google.de"];
    [self testUrl:@"www.google.de"];
    [self testUrl:@"http://www.google.de"];
    [self testUrl:@"http://google.de"];
}

出力:

INVALID: google
VALID: google.de
VALID: www.google.de
VALID: http://www.google.de
VALID: http://google.de

これは非常に興味深いようです。100%防弾ですか?
Supertecnoboff

3

Lefakirのソリューションには1つの問題があります。彼の正規表現は「http://instagram.com/p/4Mz3dTJ-ra/」と一致しません。URLコンポーネントには、数値とリテラルの文字が組み合わされています。彼の正規表現はそのようなURLに失敗します。

これが私の改善です。

"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*)+)+(/)?(\\?.*)?"

2

これを行う最も簡単な方法は次のとおりです:

- (BOOL)validateUrl: (NSURL *)candidate
{
    NSURLRequest *req = [NSURLRequest requestWithURL:candidate];
    return [NSURLConnection canHandleRequest:req];
}

私はしばらくそれを使用していますが、問題なく動作するようです。また、新しいTLD(namecheap.com/domains/new-tlds/explore.aspxでもうまく機能するようです。
julianwyz 2015年

これは無意味です。URLが無効な文字列の場合、の作成中にクラッシュするためNSURL、これの代わりにがチェックされる可能性があります。それでも古いAPIを使用しています。
Legoless

@Legolessは、try ... catchを使用できますか?
COBB 2016

2

以下のコードは、有効なURLを見つけることができます

      NSPredicate *websitePredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",@"^(((((h|H)(t|T){2}(p|P)s?)|((f|F)(t|T)(p|P)))://(w{3}.)?)|(w{3}.))[A-Za-z0-9]+(.[A-Za-z0-9-:;\?#_]+)+"];
     if ([websitePredicate evaluateWithObject:##MY_STRING##])
     {
       printf"Valid"
     }

そのようなURL


1

承認された答えは正しくありません。「-」を含むURLがあり、検証が失敗します。


1

G +リンクをサポートするためのTweeked Vaibhavの回答:

NSString *urlRegEx = @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-\\+ ./?%&amp;=]*)?";


1

末尾に/がないURLは、上記のソリューションでは正しいものとして検出されません。だから、これは役に立つかもしれません。

  extension String {
    func isValidURL() -> Bool{
        let length:Int = self.characters.count
        var err:NSError?
        var dataDetector:NSDataDetector? = NSDataDetector()
        do{
            dataDetector = try NSDataDetector(types: NSTextCheckingType.Link.rawValue)
        }catch{
            err = error as NSError
        }
        if dataDetector != nil{
            let range = NSMakeRange(0, length)
            let notFoundRange = NSRange(location: NSNotFound, length: 0)
            let linkRange = dataDetector?.rangeOfFirstMatchInString(self, options: NSMatchingOptions.init(rawValue: 0), range: range)
            if !NSEqualRanges(notFoundRange, linkRange!) && NSEqualRanges(range, linkRange!){
                return true
            }
        }else{
            print("Could not create link data detector: \(err?.localizedDescription): \(err?.userInfo)")
        }

        return false
    }
}

1

SwiftでのURL検証

詳細

Xcode 8.2.1、Swift 3

コード

列挙型URLSchemes:String

import Foundation

enum URLSchemes: String {
    case http = "http://", https = "https://", ftp = "ftp://", unknown = "unknown://"

    static func detectScheme(urlString: String) -> URLSchemes {

        if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .http) {
            return .http
        }
        if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .https) {
            return .https
        }
        if URLSchemes.isSchemeCorrect(urlString: urlString, scheme: .ftp) {
            return .ftp
        }
        return .unknown
    }

    static func getAllSchemes(separetedBy separator: String) -> String {
        return "\(URLSchemes.http.rawValue)\(separator)\(URLSchemes.https.rawValue)\(separator)\(URLSchemes.ftp.rawValue)"
    }

    private static func isSchemeCorrect(urlString: String, scheme: URLSchemes) -> Bool {
        if urlString.replacingOccurrences(of: scheme.rawValue, with: "") == urlString {
            return false
        }
        return true
    }
}

拡張文字列

import Foundation

extension String {

    var isUrl: Bool {

        // for http://regexr.com checking
        // (?:(?:https?|ftp):\/\/)(?:xn--)?(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[#-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?

        let schemes = URLSchemes.getAllSchemes(separetedBy: "|").replacingOccurrences(of: "://", with: "")
        let regex = "(?:(?:\(schemes)):\\/\\/)(?:xn--)?(?:\\S+(?::\\S*)?@)?(?:(?!10(?:\\.\\d{1,3}){3})(?!127(?:\\.\\d{1,3}){3})(?!169\\.254(?:\\.\\d{1,3}){2})(?!192\\.168(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[#-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?"


        let regularExpression = try! NSRegularExpression(pattern: regex, options: [])
        let range = NSRange(location: 0, length: self.characters.count)
        let matches = regularExpression.matches(in: self, options: [], range: range)
        for match in matches {
            if range.location == match.range.location && range.length == match.range.length {
                return true
            }
        }
        return false
    }

    var toURL: URL? {

        let urlChecker: (String)->(URL?) = { url_string in
            if url_string.isUrl, let url = URL(string: url_string) {
                return url
            }
            return nil
        }

        if !contains(".") {
            return nil
        }

        if let url = urlChecker(self) {
            return url
        }

        let scheme = URLSchemes.detectScheme(urlString: self)
        if scheme == .unknown {
            let newEncodedString = URLSchemes.http.rawValue + self
            if let url = urlChecker(newEncodedString) {
                return url
            }
        }

        return nil
    }
}

使用法

 func tests() {

    chekUrl(urlString:"http://example.com")
    chekUrl(urlString:"https://example.com")
    chekUrl(urlString:"http://example.com/dir/file.php?var=moo")
    chekUrl(urlString:"http://xn--h1aehhjhg.xn--d1acj3b")
    chekUrl(urlString:"http://www.example.com/wpstyle/?p=364")
    chekUrl(urlString:"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com")
    chekUrl(urlString:"http://example.com")
    chekUrl(urlString:"http://xn--d1acpjx3f.xn--p1ai")
    chekUrl(urlString:"http://xn--74h.damowmow.com/")
    chekUrl(urlString:"ftp://example.com:129/myfiles")
    chekUrl(urlString:"ftp://user:pass@site.com:21/file/dir")
    chekUrl(urlString:"ftp://ftp.example.com:2828/asdah%20asdah.gif")
    chekUrl(urlString:"http://142.42.1.1:8080/")
    chekUrl(urlString:"http://142.42.1.1/")
    chekUrl(urlString:"http://userid:password@example.com:8080")
    chekUrl(urlString:"http://userid@example.com")
    chekUrl(urlString:"http://userid@example.com:8080")
    chekUrl(urlString:"http://foo.com/blah_(wikipedia)#cite-1")
    chekUrl(urlString:"http://foo.com/(something)?after=parens")

    print("\n----------------------------------------------\n")

    chekUrl(urlString:".")
    chekUrl(urlString:" ")
    chekUrl(urlString:"")
    chekUrl(urlString:"-/:;()₽&@.,?!'{}[];'<>+_)(*#^%$")
    chekUrl(urlString:"localhost")
    chekUrl(urlString:"yandex.")
    chekUrl(urlString:"коряга")
    chekUrl(urlString:"http:///a")
    chekUrl(urlString:"ftps://foo.bar/")
    chekUrl(urlString:"rdar://1234")
    chekUrl(urlString:"h://test")
    chekUrl(urlString:":// should fail")
    chekUrl(urlString:"http://-error-.invalid/")
    chekUrl(urlString:"http://.www.example.com/")
}

func chekUrl(urlString: String) {
    var result = ""
    if urlString.isUrl {
        result += "url: "
    } else {
        result += "not url: "
    }
    result += "\"\(urlString)\""
    print(result)
}

結果

ここに画像の説明を入力してください


1

目的C

- (BOOL)validateUrlString:(NSString*)urlString
{
    if (!urlString)
    {
        return NO;
    }

    NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];

    NSRange urlStringRange = NSMakeRange(0, [urlString length]);
    NSMatchingOptions matchingOptions = 0;

    if (1 != [linkDetector numberOfMatchesInString:urlString options:matchingOptions range:urlStringRange])
    {
        return NO;
    }

    NSTextCheckingResult *checkingResult = [linkDetector firstMatchInString:urlString options:matchingOptions range:urlStringRange];

    return checkingResult.resultType == NSTextCheckingTypeLink && NSEqualRanges(checkingResult.range, urlStringRange);
}

お役に立てれば!


0

ユーザーが入力したものがURLかどうかを確認するつもりでしたか?文字列が含まれている場合には、例えば、チェックのために、正規表現として、単純なようすることができwww.(これはヤフーメッセンジャーをチェックし、そのようなユーザのステータスがリンクであるかどう)
の助けことを願っています


0

勝手に、KSURLFormatterインスタンスを使用して入力を検証し、NSURL処理できるものに変換することをお勧めします。


これのiOS味はありますか?
capikaw 2012

iOSでは問題なく動作するはずです。解決しない場合は、修正してプルリクエストを送信するか、問題を
Mike Abdullah


0

@Anthonyの回答を迅速に拡張しStringて、オプションのを返すカテゴリを作成しましたNSURL。がURLであることを検証できないnil場合、戻り値はですString

import Foundation

// A private global detector variable which can be reused.
private let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue)

extension String {
  func URL() -> NSURL? {
    let textRange = NSMakeRange(0, self.characters.count)
    guard let URLResult = detector.firstMatchInString(self, options: [], range: textRange) else {
      return nil
    }

    // This checks that the whole string is the detected URL. In case
    // you don't have such a requirement, you can remove this code
    // and return the URL from URLResult.
    guard NSEqualRanges(URLResult.range, textRange) else {
      return nil
    }

    return NSURL(string: self)
  }
}

0
func checkValidUrl(_ strUrl: String) -> Bool {
    let urlRegEx: String = "(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"
    let urlTest = NSPredicate(format: "SELF MATCHES %@", urlRegEx)
    return urlTest.evaluate(with: strUrl)
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.