2011-01-19 7 views
5

Ho trovato questa espressione regolare su un sito Web. Si dice che sia la migliore espressione di convalida degli URL là fuori e sono d'accordo. Diego Perini lo ha creato.NSRegularExpression per convalidare l'URL

Il problema che sto affrontando è quando si prova ad usarlo con objective-C per rilevare gli URL sulle stringhe. Ho provato a utilizzare opzioni come NSRegularExpressionAnchorsMatchLines, NSRegularExpressionIgnoreMetacharacters e altri, ma ancora senza fortuna.

L'espressione non è formattata correttamente per Objective-C? Mi sto perdendo qualcosa? Qualche idea?

Ho anche provato la regex di John Gruber, ma non riesce con alcuni URL non validi.

 Regular Expression         Explanation of expression      

^             match at the beginning 
//Protocol identifier 
(?: 
    (?:https?|ftp         http, https or ftp 
    ):\\/\\/          :// 
)?             optional 
// User:Pass authentication 
(?: 
    ^\\s+           non white spaces, 1 or more times 
    (?: 
     :^\\s*          : non white spaces, 0 or more times, optionally 
    )[email protected]            @ 
)?             optional 
//Private IP Addresses        ?! Means DO NOT MATCH ahead. So do not match any of the following 
(?: 
    (?!10           10               10.0.0.0 - 10.999.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, three times 
     ){3} 
    ) 
    (?!127           127               127.0.0.0 - 127.999.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, three times 
     ){3} 
    ) 
    (?!169\\.254         169.254              169.254.0.0 - 169.254.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    (?!192\\.168         192.168              192.168.0.0 - 192.168.999.999 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    (?!172\\.          172.              172.16.0.0 - 172.31.999.999 
     (?:                            
      1[6-9]         1 followed by any number between 6 and 9 
      |          or 
      2\\d         2 and any digit 
      |          or 
      3[0-1]         3 followed by a 0 or 1 
     ) 
     (?: 
      \\.\\d{1,3}        . 1 to 3 digits, two times 
     ){2} 
    ) 
    //First Octet IPv4        // match these. Any non network or broadcast IPv4 address 
    (?: 
     [1-9]\\d?         any number from 1 to 9 followed by an optional digit  1 - 99 
     |           or 
     1\\d\\d          1 followed by any two digits        100 - 199 
     |           or 
     2[01]\\d         2 followed by any 0 or 1, followed by a digit    200 - 219 
     |           or 
     22[0-3]          22 followed by any number between 0 and 3     220 - 223 
    ) 
    //Second and Third Octet IPv4 
    (?: 
     \\.           . 
     (?: 
      1?\\d{1,2}        optional 1 followed by any 1 or two digits     0 - 199 
      |          or 
      2[0-4]\\d        2 followed by any number between 0 and 4, and any digit  200 - 249 
      |          or 
      25[0-5]         25 followed by any numbers between 0 and 5     250 - 255 
     ) 
    ){2}           two times 
    //Fourth Octet IPv4 
    (?: 
     \\.           . 
     (?: 
      [1-9]\\d?        any number between 1 and 9 followed by an optional digit 1 - 99 
      |          or 
      1\\d\\d         1 followed by any two digits        100 - 199 
      |          or 
      2[0-4]\\d        2 followed by any number between 0 and 4, and any digit  200 - 249 
      |          or 
      25[0-4]         25 followed by any number between 0 and 4     250 - 254 
     ) 
    ) 
    //Host name 
    |            or     
    (?: 
     (?: 
      [a-z\u00a1-\uffff0-9]+-?    any letter, digit or character one or more times with optional - 
     )*           zero or more times 
     [a-z\u00a1-\uffff0-9]+      any letter, digit or character one or more times 
    ) 
    //Domain name 
    (?: 
     \\.           . 
     (?: 
      [a-z\u00a1-\uffff0-9]+-?    any letter, digit or character one or more times with optional - 
     )*           zero or more times 
     [a-z\u00a1-\uffff0-9]+      any letter, digit or character one or more times 
    )*            zero or more times 
    //TLD identifier 
    (?: 
     \\.           . 
     (?: 
      [a-z\u00a1-\uffff]{2,}     any letter, digit or character more than two times 
     ) 
    ) 
) 
//Port number 
(?: 
    :\\d{2,5}          : followed by any digit, two to five times, optionally 
)?    
//Resource path 
(?: 
    \\/[^\\s]*         /followed by an optional non space character, zero or more times 
)?             optional 
$             match at the end 

EDIT penso Ho dimenticato di dire che sto usando l'espressione nel codice seguente: (codice parziale)

NSError *error = NULL; 
NSRegularExpression *detector = [NSRegularExpression regularExpressionWithPattern:[self theRegularExpression] options:0 error:&error]; 
NSArray *links = [detector matchesInString:theText options:0 range:NSMakeRange(0, theText.length)]; 

risposta

9
^(?i)(?:(?:https?|ftp):\\/\\/)?(?:\\S+(?::\\S*)[email protected])?(?:(?:[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]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?$ 

È la migliore espressione regolare di convalida URL che ho trovato ed è spiegata sulla mia domanda. È già formattato per funzionare su Objective-C. Tuttavia, usarlo con NSRegularExpression mi ha dato tutti i tipi di problemi, compresa la mia app in crash. RegexKitLite non ha avuto problemi a gestirlo. Non so se si tratta di una limitazione delle dimensioni o di qualche bandiera non impostata. Il mio codice finale sembrava:

//First I take the string and put every word in an array, then I match every word with the regular expression 
NSArray *splitIntoWordsArray = [textToMatch componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewLineCharacterSet]]; 
NSMutableString *htmlString = [NSMutableString stringWithString:textToMatch]; 
for (NSString *theText in splitIntoWordsArray){ 
    NSEnumerator *matchEnumerator = [theText matchEnumeratorWithRegex:theRegularExpressionString]; 
    for (NSString *temp in matchEnumerator){ 
     [htmlString replaceOccurrencesOfString:temp withString:[NSString stringWithFormat:@"<a href=\"%@\">%@</a>", temp, temp] options:NSLiteralSearch range:NSMakeRange(0, [htmlString length])]; 
    } 
} 
[htmlString replaceOccurrencesOfString:@"\n" withString:@"<br />" options:NSLiteralSearch range:NSMakeRange(0, htmlString.length)]; 
//embed the text on a webView as HTML 
[webView loadHTMLString:[NSString stringWithFormat:embedHTML, [mainFont fontName], [mainFont pointSize], htmlString] baseURL:nil]; 

Il risultato: un UIWebView con un po 'HTML embedded, dove URL e email sono cliccabili. Non dimenticare di impostare dataDetectorTypes = UIDataDetectorTypeNone

Potete anche provare

NSError *error = NULL; 
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"(?i)(?:(?:https?):\\/\\/)?(?:\\S+(?::\\S*)[email protected])?(?:(?:[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]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?" options:NSRegularExpressionCaseInsensitive error:&error]; 
if (error) 
    NSLog(@"error"); 
NSString *someString = @"This is a sample of a sentence with a URL http://. http://.. http://../ http://? http://?? http://??/ http://# http://-error-.invalid/ http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com within it."; 
NSRange range = [expression rangeOfFirstMatchInString:someString options:NSMatchingCompleted range:NSMakeRange(0, [someString length])]; 
if (!NSEqualRanges(range, NSMakeRange(NSNotFound, 0))){ 
    NSString *match = [someString substringWithRange:range]; 
    NSLog(@"%@", match); 
} 
else { 
    NSLog(@"no match"); 
} 

Speranza che aiuta qualcuno in futuro

L'espressione regolare a volte causare l'applicazione per appendere, così ho deciso di utilizzare Gruber di regolare espressione modificata per riconoscere url senza protocollo o la parte www:

(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/?)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))*(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’])*) 
+0

Grazie amico per il bel post. – Jhaliya

+0

Il tuo codice gruber aggiornato è buono, ma non corrisponde a "google.com", ma corrisponde a "google.comm" e "google.co.uk": qualche idea su come modificarla? – mootymoots

+0

Amico molte grazie per l'espressione regolare. È davvero incredibile. –

7

mi sto perdendo qualcosa?

Ti manca la roba incorporata per farlo per te. C'è un oggetto pratico chiamato NSDataDetector. Lo crei per cercare determinati "tipi" di dati (come, ad esempio, NSTextCheckingTypeLink), quindi chiedigli il suo -matchesInString:options:range:.

Here's an earlier answer of mine showing how to use it.

+0

Grazie Dave per la tua risposta rapida. L'ho provato prima, ma non riconosce alcuni URL, come .asia, .info, ecc. Questo è quando l'URL non è ben formato come http://healthyhomes.asia Ecco perché sto usando un normale espressione. Utilizzando un tester online, rileva healthyhomes.asia o info.info senza la parte del protocollo. – GianPac

+0

@Dave DeLong fallito in caso di www.google.c – JAHelia

+0

Aggiornamento 2017: appena verificato NSDataDetector. 'info.info' ora funziona, ma' healthyhomes.asia' continua a non funzionare. 'www.google.c' Funziona. Non ho idea di come Safari (iOS e desktop) possa visitare 'healthyhomes.asia' se' NSDataDetector' di Foundation non supporta tale URL. –

Problemi correlati