2012-03-06 9 views
12

Estoy usando el siguiente código en mi aplicación para iPhone, tomado de http://tinyurl.com/remarkablepixels para extraer todas las URL del código .html.Uso de NSRegularExpression para extraer direcciones URL en el iPhone

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 puedo hacer 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://mydomain.com/myplayer  
All Extracted URLs: (
    "<NSExtendedRegularExpressionCheckingResult: 0x106ddb0>{728, 53}{<NSRegularExpression: 0x106bc30> http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", 
    "<NSExtendedRegularExpressionCheckingResult: 0x106ddf0>{956, 66}{<NSRegularExpression: 0x106bc30> http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", 
    "<NSExtendedRegularExpressionCheckingResult: 0x106de30>{1046, 63}{<NSRegularExpression: 0x106bc30> http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}", 
    "<NSExtendedRegularExpressionCheckingResult: 0x106de70>{1129, 67}{<NSRegularExpression: 0x106bc30> http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)? 0x1}" 
) 

Respuesta

18

matchesInString:options:range: El método 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]; 
+0

hermoso! ¡Trabajado como un encanto! Muchas gracias jonkroll! – Winston

+4

¡Funciona asombrosamente! Es posible obtener el título después de> a <. como si la url es Google, podrías obtener "Google"? – Maximilian

5

para obtener todos los enlaces de una cadena dada

NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"(?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`!()\\[\\]{};:'\".,<>?«»“”‘’]))" 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); 
} 
+0

Ningún error de solución elegante: NULL –

2

me encontré tan náuseas por la complejidad de esta simple operación ("Que todas las subseries") que hice una pequeña biblioteca que soy humildemente llamando a Unsuck que agrega cierta sensatez a NSRegularExpression en la forma de los métodos from y allMatches. He aquí cómo debería usar este recurso:

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

favor check out the unsuck source code on github y dime todas las cosas que hice mal :-)

Tenga en cuenta que (?i) hace que sea sensible a mayúsculas por lo que no es necesario especificar NSRegularExpressionCaseInsensitive.

+0

¡Eso es totalmente increíble! ¡Gracias por compartir tu biblioteca, Alex! – Winston

13

Trate NSDataDetector

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

Con NSDataDetector utilizando 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!) 
} 

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

Using 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!) 
} 
+0

fantástica respuesta. Ejemplo simple con todas las versiones. +1 – mythicalcoder

+0

No creo que necesite el. Opción reportCompletion ya que no está utilizando enumerateMatches (en: options: range: using :) – marchinram

Cuestiones relacionadas