3

I found this solution by Antony for validating URLs.

- (BOOL)isValidURL {
    NSUInteger length = [self length];
    // Empty strings should return NO
    if (length > 0) {
       NSError *error = nil;
       NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
       if (dataDetector && !error) {
          NSRange range = NSMakeRange(0, length);
          NSRange notFoundRange = (NSRange){NSNotFound, 0};
          NSRange linkRange = [dataDetector rangeOfFirstMatchInString:self options:0 range:range];
          if (!NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange)) {
             return YES;
          }
       }
       else {
          NSLog(@"Could not create link data detector: %@ %@", [error localizedDescription], [error userInfo]);
       }
    }
    return NO;
}

I want to try it but I'm coding in swift. This is what I have so far.

extension String{
    func isValidURL() -> Bool{
         let length:Int = self.characters.count
         var err:NSError? = nil
         let dataDetector:NSDataDetector?
         do{
             dataDetector = try NSDataDetector(types: NSTextCheckingType.Link.rawValue)
         }catch{
             err = error as? NSError
         }
         if dataDetector != nil && err != nil{
             let range = NSMakeRange(0, length)
             let notFoundRange = (NSRange){ NSNotFound, 0 } //How do I format this for swift?
             let linkRange = dataDetector?.rangeOfFirstMatchInString(self, options: 0, range: range)
             if !NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange){
                 return true
             }
         }else{
            print("Could not create link data detector: \(err?.localizedDescription): \(err?.userInfo)")
         }

         return false
     }
 }

The stumbling block is NSNotFound. As far as I can tell this is what swift optionals are for. How do I format that line?

Community
  • 1
  • 1
Al Martin
  • 179
  • 3
  • 15

2 Answers2

5

It's simply aggregate initialization syntax for structs in C. You can use the NSRange initializer instead:

let notFoundRange = NSRange(location: NSNotFound, length: 0)

Or, perhaps more simply:

if linkRange.location != NSNotFound { ...
Community
  • 1
  • 1
jtbandes
  • 115,675
  • 35
  • 233
  • 266
1

For those of you interested here is the same function working in swift using jtbandes answer. I've tried it on a bunch of URLs. Seems to work great..

extension String{
    func isValidURL() -> Bool{
        let length:Int = self.characters.count
        var err:NSError?
        var dataDetector:NSDataDetector? = NSDataDetector()
        do{
            dataDetector = try NSDataDetector(types: NSTextCheckingType.Link.rawValue)
        }catch{
            err = error as NSError
        }
        if dataDetector != nil{
            let range = NSMakeRange(0, length)
            let notFoundRange = NSRange(location: NSNotFound, length: 0)
            let linkRange = dataDetector?.rangeOfFirstMatchInString(self, options: NSMatchingOptions.init(rawValue: 0), range: range)
            if !NSEqualRanges(notFoundRange, linkRange!) && NSEqualRanges(range, linkRange!){
                return true
            }
        }else{
            print("Could not create link data detector: \(err?.localizedDescription): \(err?.userInfo)")
        }

        return false
    }
}
Al Martin
  • 179
  • 3
  • 15