Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check email with NSDataDetector

I have a string coming from server and want to check whether it contains expressions like phone numbers, mail address and email. I got success in case of phone number and mail address, but not email. I am using NSDataDetector for this purpose. eg

NSString *string = sourceNode.label; //coming from server

//Phone number
NSDataDetector *phoneDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber error:nil]; 
NSArray *phoneMatches = [phoneDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];

for (NSTextCheckingResult *match in phoneMatches) {

    if ([match resultType] == NSTextCheckingTypePhoneNumber) {
        NSString *matchingStringPhone = [match description];
        NSLog(@"found URL: %@", matchingStringPhone);
    }
}  

But how to do the same for email?

like image 776
Nitish Avatar asked Jan 13 '12 12:01

Nitish


5 Answers

Here's an up to date playground compatible version that builds on top of Dave Wood's and mkto's answer:

import Foundation

func isValid(email: String) -> Bool {
  do {
    let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
    let range = NSRange(location: 0, length: email.count)
    let matches = detector.matches(in: email, options: .anchored, range: range)
    guard matches.count == 1 else { return false }
    return matches[0].url?.scheme == "mailto"
  } catch {
    return false
  }
}

extension String {
  var isValidEmail: Bool {
    isValid(email: self)
  }
}

let email = "[email protected]"
isValid(email: email) // prints 'true'
email.isValidEmail // prints 'true'
like image 113
Fero Avatar answered Sep 30 '22 19:09

Fero


Here's a clean Swift version.

extension String {
    func isValidEmail() -> Bool {
        guard !self.lowercaseString.hasPrefix("mailto:") else { return false }
        guard let emailDetector = try? NSDataDetector(types: NSTextCheckingType.Link.rawValue) else { return false }
        let matches = emailDetector.matchesInString(self, options: NSMatchingOptions.Anchored, range: NSRange(location: 0, length: self.characters.count))
        guard matches.count == 1 else { return false }
        return matches[0].URL?.absoluteString == "mailto:\(self)"
    }
}

Swift 3.0 Version:

extension String {
    func isValidEmail() -> Bool {
        guard !self.lowercased().hasPrefix("mailto:") else { return false }
        guard let emailDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { return false }
        let matches = emailDetector.matches(in: self, options: NSRegularExpression.MatchingOptions.anchored, range: NSRange(location: 0, length: self.characters.count))
        guard matches.count == 1 else { return false }
        return matches[0].url?.absoluteString == "mailto:\(self)"
    }
}

Objective-C:

@implementation NSString (EmailValidator)

- (BOOL)isValidEmail {
    if ([self.lowercaseString hasPrefix:@"mailto:"]) { return NO; }

    NSDataDetector* dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
    if (dataDetector == nil) { return NO; }

    NSArray* matches = [dataDetector matchesInString:self options:NSMatchingAnchored range:NSMakeRange(0, [self length])];
    if (matches.count != 1) { return NO; }

    NSTextCheckingResult* match = [matches firstObject];
    return match.resultType == NSTextCheckingTypeLink && [match.URL.absoluteString isEqualToString:[NSString stringWithFormat:@"mailto:%@", self]];
}

@end
like image 26
Dave Wood Avatar answered Nov 03 '22 07:11

Dave Wood


if (result.resultType == NSTextCheckingTypeLink)
{
    if ([result.URL.scheme.locaseString isEqualToString:@"mailto"])
    {
        // email link
    }
    else
    {
        // url
    }
}

Email address falls into NSTextCheckingTypeLink. Simply look for "mailto:" in the URL found and you will know it is an email or URL.

like image 32
mkto Avatar answered Nov 03 '22 07:11

mkto


EDIT:

my answer has been accepted in 2012 and is pretty outdated. Please read please this one instead.

Original post:

In apple documentation, it seems that recognised types does not include email : http://developer.apple.com/library/IOs/#documentation/AppKit/Reference/NSTextCheckingResult_Class/Reference/Reference.html#//apple_ref/c/tdef/NSTextCheckingType

So I suggest you to use a Regexp. It would be like :

NSString* pattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]+";

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
if ([predicate evaluateWithObject:@"[email protected]"] == YES) {
  // Okay
} else {
  // Not found
}
like image 7
Martin Avatar answered Nov 03 '22 07:11

Martin


Try following code, see if it works for you :

NSString * mail = [email protected]
NSDataDetector * dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSTextCheckingResult * firstMatch = [dataDetector firstMatchInString:mail options:0 range:NSMakeRange(0, [mail length])];
BOOL result = [firstMatch.URL isKindOfClass:[NSURL class]] && [firstMatch.URL.scheme isEqualToString:@"mailto"];
like image 7
Hitesh Savaliya Avatar answered Nov 03 '22 06:11

Hitesh Savaliya