Comment valider une URL sur l'iPhone


90

Dans une application iPhone que je développe, il existe un paramètre dans lequel vous pouvez entrer une URL, en raison de sa forme et de sa fonction, cette URL doit être validée en ligne et hors ligne.

Jusqu'à présent, je n'ai pas été en mesure de trouver une méthode pour valider l'url, donc la question est;

Comment valider une entrée URL sur l'iPhone (Objective-C) en ligne et hors ligne?


Lisez les commentaires à sa réponse, la validation ne fonctionne pas correctement.
Thizzer

Réponses:


98

Grâce à cet article , vous pouvez éviter d'utiliser RegexKit. Voici ma solution (fonctionne pour le développement iphone avec iOS> 3.0):

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

Si vous souhaitez vérifier dans Swift ma solution ci-dessous:

 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
Cela ne fonctionne que pour les URL de type " webr.ly " ne fonctionne pas pour les URL avec des paramètres tels que youtube.com/watch?v=mqgExtdNMBk
The uSeFuL

5
((http|https)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+".Il devrait rendre http: // ou https: // optionnel.
Yeung

ne fonctionne pas pour google.com, www.google.com et aussi pour //www.google.com
Revinder le

les URL suivantes ne fonctionnent pas dans mon cas. money.cnn.com/2015/10/19/technology/apple-app-store/…
DJtiwari

@DJtiwari +1 oui ça ne marche pas as-tu trouvé une solution pour ça?
Hamza MHIRA

239

Pourquoi ne pas simplement compter sur Foundation.framework?

Cela fait le travail et ne nécessite pas 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)
}

Selon la documentation Apple:

URLWithString: crée et renvoie un objet NSURL initialisé avec une chaîne fournie.

+ (id)URLWithString:(NSString *)URLString

Paramètres

URLString: La chaîne avec laquelle initialiser l'objet NSURL. Doit être conforme à la RFC 2396. Cette méthode analyse URLString conformément aux RFC 1738 et 1808.

Valeur de retour

Un objet NSURL initialisé avec URLString. Si la chaîne était malformée, renvoie nil.


1
Je suis d'accord avec certains des autres ici. C'est une bien meilleure solution que de jouer avec les expressions régulières. Cela devrait être la réponse correctement vérifiée.
Diego Barros

1
@MrThys - Avez-vous une chance de fournir des exemples d'URL malformées que cela ne détecte pas? Ce serait formidable à savoir .. semble une excellente solution jusqu'à présent.
Don Vaughn

7
@DonamiteIsTnt L'URL http://www.aol.comhttp://www.nytimes.comréussit ce test.
Aaron Brager

1
Le code ne vérifiera pas les URL mal formées. Ex: <code> afasd </ code >, l'URL passera toujours le test
denil

39
Les documents sont faux. Ecrire quelques tests - NSURLne renvoie pas nil lorsque je passe une chaîne de @ "# @ # @ $ ##% $ # $ #", ou @ "tp: / fdfdfsfdsf". Cette méthode sera donc inutile pour vérifier les URL HTTP valides, etc.
Tony Arnold le

32

Au lieu d'écrire vos propres expressions régulières, comptez sur celles d'Apple. J'utilise une catégorie sur NSStringqui utilise NSDataDetectorpour tester la présence d'un lien dans une chaîne. Si la plage du lien trouvé par NSDataDetectorest égale à la longueur de la chaîne entière, il s'agit d'une URL valide.

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

Extrêmement intelligent. Véritable ingénierie. {Vous savez, j'ai eu un problème étrange où si je lui envoie la chaîne littéralement "<null>", il plante! Je n'ai jamais pu le comprendre.}
Fattie

Ah - c'était "<null>" dans le fils, que Apple fournit utilement comme NSNull! : O
Fattie

J'ai créé un point essentiel où j'ai commencé à ajouter des cas de test pour cette copie. Remplissez gratuitement pour en ajouter. gist.github.com/b35097bad451c59e23b1.git
Yevhen Dubinin

26

Ma solution avec 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)
}

Pour le test:

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

Résultats:

false
false
false
true
false
false
true
true
false
false
false

10

utilisez ceci-

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

1
Je l'ai copié simplement pour le validateur d'expressions régulières asp.net;)
Vaibhav Saran

parfait, le seul problème est qu'il ne reconnaît paswww.google.com/+gplusname
MuhammadBassio

5

J'ai résolu le problème en utilisant RegexKit et j'ai créé une expression régulière rapide pour valider une URL;

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

Ensuite, je vérifie si matchedString est égal à subjectString et si tel est le cas, l'url est valide :)

Corrigez-moi si mon regex est fausse;)


Je me trompe peut-être, mais je crois que regex ne valide pas les URL avec des chaînes de requête ou des ancres nommées.
hpique

Vous pouvez rendre la partie préfixe facultative en remplaçant (http | https): // par ((http | https): //) * mais cela permettrait une très grande variété d'urls
Thizzer

4

Curieusement, je n'ai pas vraiment trouvé de solution ici qui soit très simple, mais qui a quand même fait un bon travail pour la gestion http/ les httpsliens.

Gardez à l'esprit que CE N'EST PAS une solution parfaite, mais cela a fonctionné pour les cas ci-dessous. En résumé, l'expression régulière teste si l'URL commence par http://ou https://, puis vérifie au moins 1 caractère, puis vérifie un point, puis vérifie à nouveau au moins 1 caractère. Aucun espace autorisé.

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

Testé VALID par rapport à ces 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"

Testé INVALID par rapport à ces 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"

Source des URL: https://mathiasbynens.be/demo/url-regex


3

Vous pouvez l'utiliser si vous ne voulez pas httpou httpsouwww

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

exemple

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

Production:

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

Cela semble très intéressant. Est-ce 100% à l'épreuve des balles?
Supertecnoboff

3

La solution de Lefakir a un problème. Son regex ne peut pas correspondre à " http://instagram.com/p/4Mz3dTJ-ra/ ". Le composant URL a combiné des caractères numériques et littéraux. Son regex échoue à de telles URL.

Voici mon amélioration.

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

2

J'ai trouvé le moyen le plus simple de le faire:

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

Je l'utilise depuis un moment maintenant et cela semble fonctionner correctement. Il semble également bien fonctionner avec les nouveaux TLD ( namecheap.com/domains/new-tlds/explore.aspx ).
julianwyz

C'est inutile. Si votre URL est une chaîne non valide, elle plantera lors de la création d'un NSURL, ce qui pourrait être vérifié à la place de cela. Et même ainsi, il utilise une ancienne API.
Legoless

@Legoless pourrait simplement utiliser un essai ... attraper autour de lui?
COBB


1

La réponse approuvée est incorrecte. J'ai une URL avec un "-" dedans et la validation échoue.


1

Réponse de Tweeked Vaibhav pour prendre en charge les liens G +:

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


1

Certaines URL sans / à la fin ne sont pas détectées comme étant la bonne dans les solutions ci-dessus. Cela pourrait donc être utile.

  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

Validation d'URL dans Swift

Détails

Xcode 8.2.1, Swift 3

Code

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

extension String

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

Usage

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

Résultat

entrez la description de l'image ici


1

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

J'espère que cela t'aides!


0

vouliez-vous vérifier si ce que l'utilisateur a entré est une URL? Il peut être aussi simple comme une expression régulière, par exemple vérifier si la chaîne contient www.(ce qui est la façon dont les contrôles de Yahoo Messenger si le statut de l' utilisateur est un lien ou non) L'
espoir que l' aide


0

Égoïstement, je suggérerais d'utiliser une KSURLFormatterinstance à la fois pour valider l'entrée et la convertir en quelque chose qui NSURLpeut gérer.


Y a-t-il une saveur iOS à cela?
capikaw

Cela devrait fonctionner correctement sur iOS. Si ce n'est pas le cas, corrigez-le et envoyez-moi une pull request, ou déposez un problème
Mike Abdullah


0

En étendant la réponse de @ Anthony à swift, j'ai écrit une catégorie sur Stringlaquelle renvoie une option NSURL. La valeur de retour est nilsi le Stringne peut pas être validé comme URL.

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)
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.