2012-03-06 16 views
12

Korzystam z poniższego kodu w mojej aplikacji na iPhone'a, zaczerpniętego z http://tinyurl.com/remarkablepixels, aby wyodrębnić wszystkie adresy URL z pasującego kodu .html.Używanie NSRegularExpression do wyodrębniania adresów URL na telefonie iPhone

Jestem w stanie wyodrębnić pierwszy adres URL, ale potrzebuję tablicy zawierającej adresy URL: i. Mój NSArray nie zwraca NSStrings dla każdego adresu URL, ale tylko opisy obiektów.

Co zrobić, aby mój arrayOfAllMatches zwrócił wszystkie adresy URL jako 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; 

}

Oto moje wyjście 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}" 
) 

Odpowiedz

18

Sposób matchesInString:options:range: zwraca tablicę NSTextCheckingResult obiektów. Możesz użyć szybkiego wyliczania do iterowania w tablicy, wyciągania podciągu z każdego dopasowania z oryginalnego łańcucha i dodawania podłańcucha do nowej tablicy.

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

Beautiful! Pracował jak urok! Wielkie dzięki jonkroll! – Winston

+4

Działa niesamowicie! Czy można uzyskać tytuł po> do <. na przykład, jeśli adres URL to Google, możesz uzyskać "Google"? – Maximilian

5

aby wszystkie linki z danej ciąg

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

Brak eleganckiego błędu rozwiązania: NULL –

2

znalazłem się tak niedobrze złożonością tej prostej operacji („dopasować wszystkie podciągi”), które zrobiłem małą bibliotekę jestem pokornie dzwoniąc pod numer Unsuck, który dodaje trochę poprawności do NSRegularExpression w postaci metod from i allMatches. Oto jak chcesz z nich korzystać:

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

Please check out the unsuck source code on github i powiedz mi wszystko, co zrobiłem źle :-)

Zauważ, że (?i) sprawia, że ​​wielkość liter ma znaczenie, więc nie trzeba określać NSRegularExpressionCaseInsensitive.

+0

To jest całkowicie niesamowite! Dzięki za udostępnienie twojej biblioteki, Alex! – Winston

13

Spróbuj NSDataDetector

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

Z NSDataDetector użyciu 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

fantastyczna odpowiedź. Prosty przykład dla wszystkich wersji. +1 – mythicalcoder

+0

Nie sądzę, że potrzebujesz. opcja reportCompletion, ponieważ nie używasz enumerateMatches (w: options: range: using :) – marchinram