【问题标题】:How can I extract a URL from a sentence that is in a NSString?如何从 NSString 中的句子中提取 URL?
【发布时间】:2011-06-03 04:34:12
【问题描述】:

我要完成的工作如下。我有一个 NSString,其中有一个句子,其中有一个 URL。我需要能够获取在 NSString 中的任何句子中显示的 URL,例如:

假设我有这个 NSString

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

我需要能够从该 NSString 中提取 http://example.com/efg.php?EFAei687e3EsA。这个 NSString 不是静态的,并且会改变结构,并且 url 不一定在句子的同一位置。我试图研究three20代码,但对我来说毫无意义。这还能怎么做?

【问题讨论】:

  • 请参阅my answer 了解使用 Swift 3 并提供 2 种解决问题的方法的类似问题。

标签: ios regex cocoa-touch nsstring


【解决方案1】:

使用NSDataDetector:

NSString *string = @"This is a sample of a http://example.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 太棒了!!!我不知道他们是 NSDataDetector 的链接检测代码。嗯,我刚刚学到了一些新东西。谢谢戴夫,我必须测试正则表达式和您的 NSDataDector 代码,看看哪个最适合我的需要。但是,我同意您使用 Apple 的代码而不是不可靠的代码。再次感谢。我可能不得不改变我的答案。 :-)
  • @0SX 不客气。只是一个警告:这仅适用于 iOS 4+
  • 真的太棒了 +1 为你兄弟...(戴夫德隆)非常感谢您的代码解释 :)
  • 谢谢戴夫。您将如何提取该链接?使用 stringByReplacingOccurrencesOfString 是最好的方法吗?
  • @marciokoko NSTextCheckingResult 可以告诉您匹配子字符串的范围,然后您可以将其与 substringWithRange: 一起使用
【解决方案2】:

编辑:我要在这里冒昧地说你应该使用 NSDataDetector,正如 Dave 提到的那样。比正则表达式更不容易出错。


看看regular expressions。你可以构造一个简单的使用NSRegularExpression类来提取URL,或者在网上找到一个你可以使用的。有关使用该类的教程,请参阅here。


您想要的代码基本上如下所示(使用 John Gruber 的 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://example.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://example.com/efg.php?EFAei687e3EsA'

这将提取任何字符串中的第一个 URL(当然,这不会进行错误检查,因此如果字符串确实不包含任何 URL,它将不起作用,但请查看 NSRegularExpression 类看看如何绕过它。

【讨论】:

    【解决方案3】:

    这样使用:

    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 中的所有链接

    【讨论】:

      【解决方案4】:

      使用这个:

      NSURL *url;
      NSArray *listItems = [someString componentsSeparatedByString:@" "];
      
      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];
      }
      

      【讨论】:

      • +1 感谢您的代码,这实际上也可以工作,但以数组格式可能对某些事情有用:-) 再次感谢。
      【解决方案5】:

      你需要两件事:

      1. 将正则表达式添加到 NSString 的类别(即 RegexKit)
      2. Matching Regex for URLS。

      问候,

      【讨论】:

      • @0SX,请务必使用 REGEX 和 gruber 的 Urls 匹配架构。这是获取 URL 子字符串的最佳方式。
      【解决方案6】:

      你提到了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;
                  }
              }
          }
      }
      

      每次在第一个 if 部分之后执行 [self addNode:node]; 时,它都会添加一个找到的 URL。这应该让你开始!希望这可以帮助。 :)

      【讨论】:

      • 当然,如果为 iPhone 编译,没有理由使用像这样的复杂代码而不是 NSRegularExpression 类。
      【解决方案7】:

      斯威夫特 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

      【讨论】:

      • 此处投错票。请有人投票支持它!它有效!
      【解决方案8】:

      使用 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)
          }
      }
      

      【讨论】:

      • 这个答案没有问题,我又测试过了,效果很好!!!!!!
      • 我对此投了反对票,然后在我的源数据中发现了一个错误。这行得通,对不起!
      【解决方案9】:

      Swift 4.x
      Xcode 12.x

      let string = "This is a test with the URL https://www.hackingwithswift.com to be detected. www.example.com"
      let types: NSTextCheckingResult.CheckingType = [ .link]
      let detector = try? NSDataDetector(types: types.rawValue)
      detector?.enumerateMatches(in: string, options: [], range: NSMakeRange(0, (string as NSString).length)) { (result, flags, _) in
          if(result?.url != nil){
              print(result?.url)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-04-06
        • 1970-01-01
        • 2018-12-22
        • 2012-09-13
        • 1970-01-01
        • 2012-11-05
        • 1970-01-01
        • 2011-12-14
        • 1970-01-01
        相关资源
        最近更新 更多