Проверьте электронную почту с NSDataDetector - PullRequest
6 голосов
/ 13 января 2012

У меня есть строка с сервера, и я хочу проверить, содержит ли она такие выражения, как номера телефонов, почтовый адрес и адрес электронной почты.Я добился успеха в случае номера телефона и почтового адреса, но не электронной почты.Я использую NSDataDetector для этой цели.например,

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

Но как сделать то же самое для электронной почты?

Ответы [ 6 ]

27 голосов
/ 18 июля 2013
if(result.resultType == NSTextCheckingTypeLink)
{
    if([result.URL.absoluteString rangeOfString:@"mailto:"].location != NSNotFound)
    {
        // email link
    }
    else
    {
        // url
    }
}

Адрес электронной почты попадает в NSTextCheckingTypeLink. Просто найдите «mailto:» в найденном URL, и вы поймете, что это электронное письмо или URL.

8 голосов
/ 30 августа 2012

Попробуйте следующий код, посмотрите, работает ли он у вас:

NSString * mail = so@so.com
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"];
4 голосов
/ 29 января 2016

Вот чистая версия Swift.

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:

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
4 голосов
/ 13 января 2012

В документации Apple, похоже, что распознанные типы не включают электронную почту: http://developer.apple.com/library/IOs/#documentation/AppKit/Reference/NSTextCheckingResult_Class/Reference/Reference.html#//apple_ref/c/tdef/NSTextCheckingType

Поэтому я предлагаю вам использовать регулярное выражение. Это было бы как:

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

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
if ([predicate evaluateWithObject:@"johndoe@example.com"] == YES) {
  // Okay
} else {
  // Not found
}

РЕДАКТИРОВАТЬ:

Поскольку @dunforget получил лучшее решение, несмотря на мое принятое, прочитайте, пожалуйста, его ответ .

0 голосов
/ 20 октября 2016

Кажется, теперь детектор работает для электронной почты?

let types = [NSTextCheckingType.Link, NSTextCheckingType.PhoneNumber] as NSTextCheckingType
responseAttributedLabel.enabledTextCheckingTypes = types.rawValue

И я могу нажать на электронную почту.Я использую TTTAttributedLabel, хотя.

0 голосов
/ 14 февраля 2015

Вот пример электронной почты в Swift 1.2.Не стоит проверять все крайние случаи, но это хорошее место для начала.

func isEmail(emailString : String)->Bool {

    // need optional - will be nil if successful
    var error : NSError?

    // use countElements() with Swift 1.1
    var textRange = NSMakeRange(0, count(emailString))

    // Link type includes email (mailto)
    var detector : NSDataDetector = NSDataDetector(types: NSTextCheckingType.Link.rawValue, error: &error)!

    if error == nil {

    // options value is ignored for this method, but still required! 
    var result = detector.firstMatchInString(emailString, options: NSMatchingOptions.Anchored, range: textRange)

        if result != nil {

            // check range to make sure a substring was not detected
            return result!.URL!.scheme! == "mailto" && (result!.range.location == textRange.location) && (result!.range.length == textRange.length)

        }

    } else {

        // handle error
    }

    return false
}

let validEmail = isEmail("someone@site.com") // returns true
...