2012-03-06 19 views
12

Sto utilizzando il seguente codice sull'app per iPhone, preso da http://tinyurl.com/remarkablepixels per estrarre tutti gli URL dal codice .html con striping.Utilizzo di NSRegularExpression per estrarre URL su iPhone

Sono in grado di estrarre solo il primo URL, ma ho bisogno di un array contenente tutti gli URL. Il mio NSArray non restituisce NSStrings per ciascun URL, ma solo le descrizioni degli oggetti.

Come posso rendere il mio arrayOfAllMatches restituire tutti gli URL, come 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; 

}

Qui è la mia uscita 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}" 
) 

risposta

18

Il metodo matchesInString:options:range: restituisce un array di oggetti NSTextCheckingResult. È possibile utilizzare l'enumerazione rapida per scorrere l'array, estrarre la sottostringa di ogni corrispondenza dalla stringa originale e aggiungere la sottostringa a un nuovo array.

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

Bella! Ha funzionato come un fascino! Grazie mille jonkroll! – Winston

+4

Funziona incredibilmente! È possibile ottenere il titolo dopo <> a <. come se l'url fosse Google potresti ottenere "Google"? – Maximilian

5

per ottenere tutti i link da una data stringa

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

Nessun errore elegante soluzione: NULL –

2

mi sono trovato così nauseato dalla complessità di questa semplice operazione ("hanno tutte le sottostringhe") che ho fatto una piccola biblioteca sono umilmente chiamando Unsuck che aggiunge un po 'di sanità mentale a NSRegularExpression sotto forma di metodi from e allMatches. Ecco come li usereste:

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

prega check out the unsuck source code on github e mi dicono tutte le cose che ho fatto male :-)

Nota che (?i) rende case insensitive quindi non è necessario specificare NSRegularExpressionCaseInsensitive.

+0

Questo è assolutamente fantastico! Grazie per aver condiviso la tua biblioteca, Alex! – Winston

13

Prova NSDataDetector

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

Con NSDataDetector utilizzando 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

risposta fantastica. Semplice esempio con tutte le versioni. +1 – mythicalcoder

+0

Non penso che tu abbia bisogno del. reportCompletion option poiché non stai usando enumerateMatches (in: options: range: using :) – marchinram