0SX
0SX

Reputation: 1292

How can I extract a URL from a sentence that is in a NSString?

What I'm trying to accomplish is as follows. I have a NSString with a sentence that has a URL within the sentience. I'm needing to be able to grab the URL that is presented within any sentence that is within a NSString so for example:

Let's say I had this NSString

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

I need to be able to extract http://example.com/efg.php?EFAei687e3EsA from within that NSString. This NSString isn't static and will be changing structure and the url will not necessarily be in the same spot of the sentence. I've tried to look into the three20 code but it makes no sense to me. How else can this be done?

Upvotes: 25

Views: 12669

Answers (9)

Abdul Karim
Abdul Karim

Reputation: 4523

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

Upvotes: 0

Ishu
Ishu

Reputation: 12787

use this:

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];
}

Upvotes: 3

Itai Ferber
Itai Ferber

Reputation: 29764

Edit: I'm going to go out on a limb here and say you should probably use NSDataDetector as Dave mentions. Far less prone to error than regular expressions.


Take a look at regular expressions. You can construct a simple one to extract the URL using the NSRegularExpression class, or find one online that you can use. For a tutorial on using the class, see here.


The code you want essentially looks like this (using John Gruber's 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'

That will extract the first URL in any string (of course, this does no error checking, so if the string really doesn't contain any URL's it won't work, but take a look at the NSRegularExpression class to see how to get around it.

Upvotes: 23

Dave DeLong
Dave DeLong

Reputation: 243146

Use an 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);
  }
}

This way you don't have to rely on an unreliable regular expression, and as Apple upgrades their link detection code, you get those improvements for free.

Upvotes: 92

KarimIhab
KarimIhab

Reputation: 173

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

Upvotes: 2

user3722523
user3722523

Reputation: 1790

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

Upvotes: 3

Ahmet Kazim G&#252;nay
Ahmet Kazim G&#252;nay

Reputation: 1062

Use 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);

     }
 }];

This will Output the all links in your someString one by one

Upvotes: 5

donkim
donkim

Reputation: 13137

Funny you mention three20, that was the first place I was going to go look for the answer. Here's the method from 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;
            }
        }
    }
}

Every time it does [self addNode:node]; after the first if part, it's adding a found URL. This should get you started! Hope this helps. :)

Upvotes: 2

Cesar A. Rivas
Cesar A. Rivas

Reputation: 1355

you need two things:

  1. A category that adds regex to NSString (i.e. RegexKit)
  2. Matching Regex for URLS.

regards,

Upvotes: 2

Related Questions