2011-01-04 2 views
22

То, что я пытаюсь сделать, заключается в следующем. У меня есть NSString с предложением, в котором есть URL-адрес. Я необходимости быть в состоянии захватить URL, что представлено в любом предложении, которое в NSString так, например:Как извлечь URL из предложения, которое находится в NSString?

Скажем, у меня была эта NSString

NSString *someString = @"This is a sample of a http://abc.com/efg.php?EFAei687e3EsA sentence with a URL within it."; 

Мне нужно, чтобы иметь возможность извлечь http://abc.com/efg.php?EFAei687e3EsA из этого NSString. Этот NSString не является статичным и будет меняться, и URL-адрес не обязательно будет находиться в одном и том же месте предложения. Я попытался заглянуть в код три20, но для меня это не имеет смысла. Как еще это можно сделать? Спасибо за помощь.

+0

См. [Мой ответ] (http://stackoverflow.com/a/25574255/1966109) по аналогичному вопросу, который использует Swift 3 и дает 2 способа решить вашу проблему. –

ответ

20

Редактировать: Я собираюсь выйти на конечность здесь и сказать, что вы, вероятно, должны использовать NSDataDetector, как упоминает Дэйв. Гораздо меньше подвержены ошибкам, чем регулярные выражения.


Посмотрите на regular expressions. Вы можете создать простой, чтобы извлечь URL-адрес, используя класс NSRegularExpression (доступный только на iPhone, но поскольку это таргетинг, вы в порядке) или найдите один онлайн-ресурс, который вы можете использовать. Учебник по использованию класса см. В разделе here.


Код, который вы хотите, по существу, выглядит следующим образом (с помощью Джона Грубера super URL regex):

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 = @"This is a sample of a http://abc.com/efg.php?EFAei687e3EsA sentence with a URL within it."; 
NSString *match = [someString substringWithRange:[expression rangeOfFirstMatchInString:someString options:NSMatchingCompleted range:NSMakeRange(0, [someString length])]]; 
NSLog(@"%@", match); // Correctly prints 'http://abc.com/efg.php?EFAei687e3EsA' 

Это будет извлечь первый URL в любой строке (конечно, это не делает никакой проверки ошибок, так что если строка действительно не содержит URL, он не будет работать, но посмотрите на NSRegularExpression класс, чтобы увидеть, как обойти это

+0

+1 и правильный ответ !!! Это именно то, что я хотел, и не говоря уже о том, что это было легко, как пирог для реализации. Большое спасибо за пример кода A ++. Работает безупречно !!! – 0SX

+0

Отлично! Рад, что это сработало для вас. –

+0

Отличный ответ ... –

2

вам нужны две вещи:.

  1. Категория, которая добавляет регулярное выражение к NSString (т. RegexKit)
  2. Matching Regex for URLS.

С уважением,

+0

+1 Спасибо, много помогли. – 0SX

+0

@ 0SX, обязательно используйте схему соответствия REGEX и gruber для Urls. Это лучший способ получить подстроку URL. –

+0

Сделаю, Еще раз спасибо Цезарь! – 0SX

2

Смешной вы упоминаете Three20, это было первое место, где я собирался идти искать ответ. Вот метод из Three20:

- (void)parseURLs:(NSString*)string { 
    NSInteger index = 0; 
    while (index < string.length) { 
     NSRange searchRange = NSMakeRange(index, string.length - index); 
     NSRange startRange = [string rangeOfString:@"http://" options:NSCaseInsensitiveSearch 
          range:searchRange]; 
     if (startRange.location == NSNotFound) { 
      NSString* text = [string substringWithRange:searchRange]; 
      TTStyledTextNode* node = [[[TTStyledTextNode alloc] initWithText:text] autorelease]; 
      [self addNode:node]; 
      break; 
     } else { 
      NSRange beforeRange = NSMakeRange(searchRange.location, startRange.location - searchRange.location); 
      if (beforeRange.length) { 
       NSString* text = [string substringWithRange:beforeRange]; 
       TTStyledTextNode* node = [[[TTStyledTextNode alloc] initWithText:text] autorelease]; 
       [self addNode:node]; 
      } 

      NSRange searchRange = NSMakeRange(startRange.location, string.length - startRange.location); 
      NSRange endRange = [string rangeOfString:@" " options:NSCaseInsensitiveSearch 
          range:searchRange]; 
      if (endRange.location == NSNotFound) { 
       NSString* URL = [string substringWithRange:searchRange]; 
       TTStyledLinkNode* node = [[[TTStyledLinkNode alloc] initWithText:URL] autorelease]; 
       node.URL = URL; 
       [self addNode:node]; 
       break; 
      } else { 
       NSRange URLRange = NSMakeRange(startRange.location, 
             endRange.location - startRange.location); 
       NSString* URL = [string substringWithRange:URLRange]; 
       TTStyledLinkNode* node = [[[TTStyledLinkNode alloc] initWithText:URL] autorelease]; 
       node.URL = URL; 
       [self addNode:node]; 
       index = endRange.location; 
      } 
     } 
    } 
} 

Каждый раз, когда он делает [self addNode:node]; после первой if части, это добавление найденной URL. Это должно заставить вас начать! Надеюсь это поможет. :)

+0

+1 Спасибо, я попытался найти этот код, но я сдался. Большое спасибо за код. – 0SX

+0

Конечно, если компилировать для iPhone, нет причин использовать такой свернутый код вместо класса 'NSRegularExpression'. –

3

использовать этот

NSURL *url; 
    NSMutableArray *listItems = [[someString componentsSeparatedByString:@" "] mutableCopy]; 

for(int i=0;i<[listItems count];i++) 
{ 
    NSString *str=[listItems objectAtIndex:i]; 
     if ([str rangeOfString:@"http://"].location == NSNotFound) 
      NSLog(@"Not url"); 
     else 
     url=[NSURL URLWithString:str]; 

} 
+0

+1 Спасибо за ваш код, это действительно работает также, но в формате массива, который может быть полезен для некоторых вещей :-) Еще раз спасибо. – 0SX

85

Используйте NSDataDetector:

NSString *string = @"This is a sample of a http://abc.com/efg.php?EFAei687e3EsA sentence with a URL within it."; 
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil]; 
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])]; 
for (NSTextCheckingResult *match in matches) { 
    if ([match resultType] == NSTextCheckingTypeLink) { 
    NSURL *url = [match URL]; 
    NSLog(@"found URL: %@", url); 
    } 
} 

Таким образом, вы не должны полагаться на ненадежном регулярное выражение, и, как Apple, обновляет свой код обнаружения ссылку, вы получаете эти улучшения бесплатно.

+1

+1 Удивительный !!! Я не знал, что это код обнаружения ссылок для NSDataDetector. Ну, я только что узнал что-то новое. Спасибо Дэйву, мне нужно будет проверить как регулярное выражение, так и ваш код NSDataDector, чтобы узнать, какие из них лучше всего подходят мне. Тем не менее, я с вами, скорее, использовал код Apple, а не ненадежный код. Еще раз спасибо. Мне просто нужно изменить свой ответ. :-) – 0SX

+1

@ 0SX добро пожаловать. Просто предостережение: это работает только на iOS 4+ –

+1

, это действительно хорошо, а не на регулярном выражении. – Tirth

4

Использование Like This:

NSError *error = nil; 
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink 
                  error:&error]; 

[detector enumerateMatchesInString:someString 
          options:0 
          range:NSMakeRange(0, someString.length) 
         usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) 
{ 
    if (result.resultType == NSTextCheckingTypeLink) 
    { 
     NSString *str = [NSString stringWithFormat:@"%@",result.URL]; 
     NSLOG(%@,str); 

    } 
}]; 

Это будет выводить все ссылки в SomeString один на один

1

Swift 2:

let input = "This is a test with the URL https://www.hackingwithswift.com to be detected." 
let detector = try! NSDataDetector(types: NSTextCheckingType.Link.rawValue) 
let matches = detector.matchesInString(input, options: [], range: NSMakeRange(0, input.characters.count)) 

for match in matches { 
    let url = (input as NSString).substringWithRange(match.range) 
    print(url) 
} 

Source

+0

Неверный нижний предел здесь. пожалуйста, кто-то откликнется! Оно работает! –

1

Использование Swift 2.2 - NSDataDetector

let string = "here is the link www.google.com" 
let types: NSTextCheckingType = [ .Link] 
let detector = try? NSDataDetector(types: types.rawValue) 
detector?.enumerateMatchesInString(string, options: [], range: NSMakeRange(0, (string as NSString).length)) { (result, flags, _) in 
    if(result?.URL != nil){ 
     print(result?.URL) 
    } 
} 
+0

нет ничего плохого в этом ответе, я снова тестировал, и он отлично работает !!!!! – KarimIhab

+1

Я проигнорировал это, а затем нашел ошибку в моих исходных данных. Это работает, извините! –

Смежные вопросы