Usar NSRegularExpression para extraer URL en el iPhone

Estoy usando el siguiente código en mi aplicación de iPhone, tomado de aquí para extraer todas las URL del código .html.

Solo puedo extraer la primera URL, pero necesito una matriz que contenga todas las URL. Mi NSArray no devuelve NSStrings para cada URL, sino solo las descripciones de los objetos.

¿Cómo hago que mi arrayOfAllMatches devuelva todas las URL como NSStrings?

 -(NSArray *)stripOutHttp:(NSString *)httpLine { // Setup an NSError object to catch any failures NSError *error = NULL; // create the NSRegularExpression object and initialize it with a pattern // the pattern will match any http or https url, with option case insensitive NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)?" options:NSRegularExpressionCaseInsensitive error:&error]; // create an NSRange object using our regex object for the first match in the string httpline NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:httpLine options:0 range:NSMakeRange(0, [httpLine length])]; NSArray *arrayOfAllMatches = [regex matchesInString:httpLine options:0 range:NSMakeRange(0, [httpLine length])]; // check that our NSRange object is not equal to range of NSNotFound if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0))) { // Since we know that we found a match, get the substring from the parent string by using our NSRange object NSString *substringForFirstMatch = [httpLine substringWithRange:rangeOfFirstMatch]; NSLog(@"Extracted URL: %@",substringForFirstMatch); NSLog(@"All Extracted URLs: %@",arrayOfAllMatches); // return all matching url strings return arrayOfAllMatches; } return NULL; 

}

Aquí está mi salida NSLog:

 Extracted URL: http://example.com/myplayer All Extracted URLs: ( "{728, 53}{ http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", "{956, 66}{ http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", "{1046, 63}{ http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", "{1129, 67}{ http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}" ) 

El método matchesInString:options:range: devuelve una matriz de objetos NSTextCheckingResult . Puede usar la enumeración rápida para iterar a través de la matriz, extraer la subcadena de cada coincidencia de su cadena original y agregar la subcadena a una nueva matriz.

 NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)?" options:NSRegularExpressionCaseInsensitive error:&error]; NSArray *arrayOfAllMatches = [regex matchesInString:httpLine options:0 range:NSMakeRange(0, [httpLine length])]; NSMutableArray *arrayOfURLs = [[NSMutableArray alloc] init]; for (NSTextCheckingResult *match in arrayOfAllMatches) { NSString* substringForMatch = [httpLine substringWithRange:match.range]; NSLog(@"Extracted URL: %@",substringForMatch); [arrayOfURLs addObject:substringForMatch]; } // return non-mutable version of the array return [NSArray arrayWithArray:arrayOfURLs]; 

Pruebe NSDataDetector

 NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil]; NSArray *matches = [linkDetector matchesInString:text options:0 range:NSMakeRange(0, [text length])]; 

Con NSDataDetector usando Swift:

 let types: NSTextCheckingType = .Link var error : NSError? let detector = NSDataDetector(types: types.rawValue, error: &error) var matches = detector!.matchesInString(text, options: nil, range: NSMakeRange(0, count(text))) for match in matches { println(match.URL!) } 

Usando Swift 2.0:

 let text = "http://www.google.com. http://www.bla.com" let types: NSTextCheckingType = .Link let detector = try? NSDataDetector(types: types.rawValue) guard let detect = detector else { return } let matches = detect.matchesInString(text, options: .ReportCompletion, range: NSMakeRange(0, text.characters.count)) for match in matches { print(match.URL!) } 

Usando Swift 3.0

 let text = "http://www.google.com. http://www.bla.com" let types: NSTextCheckingResult.CheckingType = .link let detector = try? NSDataDetector(types: types.rawValue) let matches = detector?.matches(in: text, options: .reportCompletion, range: NSMakeRange(0, text.characters.count)) for match in matches! { print(match.url!) } 

para obtener todos los enlaces de una cadena dada

 NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"(?i)\\b((?:[az][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][az]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”'']))" options:NSRegularExpressionCaseInsensitive error:NULL]; NSString *someString = @"www.facebook.com/link/index.php This is a sample www.google.com of a http://abc.com/efg.php?EFAei687e3EsA sentence with a URL within it."; NSArray *matches = [expression matchesInString:someString options:NSMatchingCompleted range:NSMakeRange(0, someString.length)]; for (NSTextCheckingResult *result in matches) { NSString *url = [someString substringWithRange:result.range]; NSLog(@"found url:%@", url); } 

Me encontré tan nauseabundo por la complejidad de esta simple operación (“unir TODAS las subcadenas”) que hice una pequeña biblioteca a la que humildemente llamo Unsuck, que agrega cierta cordura a NSRegularExpression en la forma de los métodos from y allMatches . Así es como los usarías:

 NSRegularExpression *re = [NSRegularExpression from: @"(?i)\\b(https?://.*)\\b"]; // or whatever your favorite regex is; Hossam's seems pretty good NSArray *matches = [re allMatches:httpLine]; 

Por favor revisa el código fuente de unsuck en github y cuéntame todo lo que hice mal 🙂

Tenga en cuenta que (?i) hace insensible a mayúsculas y minúsculas, por lo que no necesita especificar NSRegularExpressionCaseInsensitive .