Come convalidare un URL su iPhone


90

In un'app per iPhone che sto sviluppando, è presente un'impostazione in cui è possibile inserire un URL, a causa della forma e della funzione questo URL deve essere convalidato sia online che offline.

Finora non sono riuscito a trovare alcun metodo per convalidare l'URL, quindi la domanda è;

Come convalido un URL immesso sull'iPhone (Objective-C) online e offline?


Leggi i commenti alla sua risposta, la convalida non funziona correttamente.
Thizzer

Risposte:


98

Grazie a questo post , puoi evitare di usare RegexKit. Ecco la mia soluzione (funziona per lo sviluppo di iPhone con 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];
}

Se vuoi controllare Swift la mia soluzione fornita di seguito:

 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
Funziona solo per gli URL di tipo " webr.ly " non funziona per gli URL con parametri come youtube.com/watch?v=mqgExtdNMBk
UTENTE

5
((http|https)://)?((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"Dovrebbe rendere http: // o https: // opzionale.
Yeung

non funziona per google.com, www.google.com e anche per //www.google.com
Revinder

i seguenti URL non funzionano nel mio caso. money.cnn.com/2015/10/19/technology/apple-app-store/…
DJtiwari

@DJtiwari +1 sì non funziona hai trovato qualche soluzione per questo?
Hamza MHIRA

239

Perché invece non fare semplicemente affidamento su Foundation.framework?

Questo fa il lavoro e non richiede 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)
}

Secondo la documentazione Apple:

URLWithString: crea e restituisce un oggetto NSURL inizializzato con una stringa fornita.

+ (id)URLWithString:(NSString *)URLString

Parametri

URLString: La stringa con cui inizializzare l'oggetto NSURL. Deve essere conforme a RFC 2396. Questo metodo analizza URLString in base a RFC 1738 e 1808.

Valore di ritorno

Un oggetto NSURL inizializzato con URLString. Se la stringa non è valida, restituisce nil.


1
Sono d'accordo con alcuni degli altri qui. Questa è una soluzione molto migliore che armeggiare con le espressioni regolari. Questa dovrebbe essere la risposta corretta.
Diego Barros

1
@MrThys - C'è qualche possibilità che tu possa fornire esempi di quali URL non validi non vengono rilevati? Sarebbe bello saperlo .. sembra un'ottima soluzione finora.
Don Vaughn

7
@DonamiteIsTnt L'URL http://www.aol.comhttp://www.nytimes.comsupera questo test.
Aaron Brager

1
Il codice non controllerà l'URL non valido. Es: <code> afasd </ code >, l'URL supererà comunque il test
denil

39
I documenti sono sbagliati. Scrivi alcuni test - NSURLnon restituisce zero quando passo una stringa di @ "# @ # @ $ ##% $ # $ #", o @ "tp: / fdfdfsfdsf". Quindi questo metodo sarà inutile per controllare URL HTTP validi e simili.
Tony Arnold,

32

Invece di scrivere le tue espressioni regolari, affidati a quelle di Apple. Ho utilizzato una categoria su NSStringquella utilizza NSDataDetectorper verificare la presenza di un collegamento all'interno di una stringa. Se l'intervallo del collegamento trovato da è NSDataDetectoruguale alla lunghezza dell'intera stringa, si tratta di un URL valido.

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

Estremamente intelligente. Vera ingegneria. {Sai, ho avuto uno strano problema per cui se gli mando la stringa letteralmente "<null>", si blocca! Non sono mai riuscito a capirlo.}
Fattie

Ah - era "<null>" nel figlio, che Apple fornisce utilmente come NSNull! : O
Fattie

Ho creato una sintesi in cui ho iniziato ad aggiungere casi di test per questo frammento. Compila gratuitamente per aggiungere altro. gist.github.com/b35097bad451c59e23b1.git
Yevhen Dubinin

26

La mia soluzione con 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)
}

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

Risultati:

false
false
false
true
false
false
true
true
false
false
false

10

Usa questo-

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

1
l'ho copiato semplicemente per il validatore di espressioni regolari asp.net;)
Vaibhav Saran

perfetto, l'unico problema è che non riconoscewww.google.com/+gplusname
MuhammadBassio

5

Ho risolto il problema utilizzando RegexKit e ho creato una rapida regex per convalidare un URL;

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

Quindi controllo se matchedString è uguale a subjectString e se è così l'url è valido :)

Correggimi se la mia regex è sbagliata;)


Potrei sbagliarmi, ma credo che regex non convalidi gli URL con stringhe di query o ancore denominate.
hpique

È possibile rendere facoltativa la parte del prefisso sostituendo (http | https): // con ((http | https): //) * ma ciò consentirebbe un'ampia varietà di URL
Thizzer

4

Stranamente, non ho trovato una soluzione molto semplice qui, ma ho comunque fatto un buon lavoro per la gestione http/ i httpscollegamenti.

Tieni presente che QUESTA NON È una soluzione perfetta, ma ha funzionato per i casi seguenti. In sintesi, la regex verifica se l'URL inizia con http://o https://, quindi verifica la presenza di almeno 1 carattere, quindi verifica la presenza di un punto e quindi verifica di nuovo la presenza di almeno 1 carattere. Non sono ammessi spazi.

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

VALIDO testato rispetto a questi 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"

Testato INVALID rispetto a questi 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"

Fonte degli URL: https://mathiasbynens.be/demo/url-regex


3

Puoi usarlo se non vuoi httpo httpsowww

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

esempio

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

Produzione:

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

Questo sembra molto interessante. È a prova di proiettile al 100%?
Supertecnoboff

3

La soluzione di Lefakir ha un problema. La sua regex non può corrispondere a " http://instagram.com/p/4Mz3dTJ-ra/ ". Il componente URL ha un carattere numerico e letterale combinato. La sua espressione regolare non riesce a tali URL.

Ecco il mio miglioramento.

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

2

Ho trovato il modo più semplice per farlo è così:

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

Lo sto usando da un po 'di tempo e sembra funzionare bene. Sembra anche funzionare bene con i nuovi TLD ( namecheap.com/domains/new-tlds/explore.aspx ).
julianwyz

Questo è inutile. Se il tuo URL è una stringa non valida, si bloccherà durante la creazione di un NSURL, in modo che possa essere spuntato al posto di questo. E anche così utilizza la vecchia API.
Legoless

@Legoless potrebbe usare solo una prova ... aggirarlo?
COBB


1

La risposta approvata non è corretta. Ho un URL con un "-" e la convalida non riesce.


1

Risposta di Vaibhav tweeked per supportare i link G +:

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


1

Alcuni URL senza / alla fine non vengono rilevati come quelli corretti nelle soluzioni precedenti. Quindi questo potrebbe essere 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

Convalida dell'URL in Swift

Dettagli

Xcode 8.2.1, Swift 3

Codice

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

stringa di estensione

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

Utilizzo

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

Risultato

inserisci qui la descrizione dell'immagine


1

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

Spero che questo ti aiuti!


0

volevi controllare se quello che l'utente ha inserito è un URL? Può essere semplice come un'espressione regolare, ad esempio controllare se la stringa contiene www.(questo è il modo in cui yahoo messenger controlla se lo stato dell'utente è un collegamento o meno)
Spero che aiuti


0

Egoisticamente, suggerirei di utilizzare KSURLFormatterun'istanza sia per convalidare l'input sia per convertirlo in qualcosa in NSURLgrado di gestire.


C'è un sapore iOS di questo?
capikaw

Dovrebbe funzionare bene su iOS. In caso contrario, risolverlo e inviarmi una richiesta pull o presentare un problema
Mike Abdullah


0

Estendendo la risposta di @ Anthony a swift, ho scritto una categoria in Stringcui restituisce un optional NSURL. Il valore restituito è nilse Stringnon può essere convalidato come un 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)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.