Unable get range from NSString for NSURL absoluteString

142 Views Asked by At

I'm developing the chat application, where the text entered has to be detected if its URL. If so, change its color and underline it. Please have a look at below screenshot :

color

To change the color of the url I've used following code:

NSString *urlString = [[detetctedURL absoluteString] stringByRemovingPercentEncoding];

            /* *detetctedURL is detected url from entered text using NSDataDetector
            /* *for messageText http://stackoverflow.com/somefolder/any-[thing]-etc, the detectedURL is http://stackoverflow.com/somefolder/any-%5Bthing%5B-etc */

            NSRange r = [messageText rangeOfString:urlString];
            if (r.location != NSNotFound)
            {
                 //colorFromHex 4285f4
                 [atext addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:66.0/255.0 green:133.0/255.0 blue:244.0/255.0 alpha:1.0] range:r];
                 [atext addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:r];
                 //set attributed text (atext) to UILabel               
            }

How can I format detected URLs correctly if the messageText contains the URL with both special character and percent encoding both, or only percent encoding ?

Thanks!

Update :

With the help of following code, I was able to get the required range. However, its working almost fine for most of the links, but not all like in case if there is charcters such as ']-('.

NSString *urlString = [url absoluteString];
        NSRange r = [messageText rangeOfString:urlString];
        BOOL foundRange = YES;
        if (r.location == NSNotFound)
        {
            foundRange = NO;
            //for umlauts or special characters
            urlString = [[url absoluteString] stringByRemovingPercentEncoding];
            r = [messageText rangeOfString:urlString];
            if (r.location == NSNotFound)
            {
                //for white space in url
                urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
                r = [messageText rangeOfString:urlString];

                if (r.location == NSNotFound)
                {
                    urlString = [url absoluteString];
                    NSString *prefix = url.scheme;
                    if(prefix)
                    {
                        prefix = [prefix stringByAppendingString:@"://"];
                        urlString = [urlString stringByReplacingOccurrencesOfString:prefix withString:@""];
                        r = [messageText rangeOfString:urlString];
                        if (r.location == NSNotFound)
                        {
                            urlString = [urlString stringByRemovingPercentEncoding];
                            r = [messageText rangeOfString:urlString];
                            if (r.location == NSNotFound)
                            {
                                urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
                                r = [messageText rangeOfString:urlString];
                                if (r.location != NSNotFound){ foundRange = YES; }
                            }else{ foundRange = YES; }
                        }else{ foundRange = YES; }
                    }
                }else{ foundRange = YES; }
            }else{ foundRange = YES; }
        }

        if (foundRange)
        {
            //colorFromHex 4285f4
            [atext addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:66.0/255.0 green:133.0/255.0 blue:244.0/255.0 alpha:1.0] range:r];

            [atext addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:r];

            myLabel.attributedText = atext; 
        }
2

There are 2 best solutions below

0
vinothp On

Use NSDataDetector to find and highlight url.

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

NSArray* matches = [detector matchesInString: source 
                                     options: 0 
                                       range: NSMakeRange(0, [source length])];

You can use this to find phone numbers, address etc.

1
Thomas Deniau On

Set .dataDetectorTypes on your text view instead of trying to change the color yourself. The UITextView will take care of highlighting itself.