Проверьте электронную почту с NSDataDetector
У меня есть строка с сервера, и я хочу проверить, содержит ли она такие выражения, как номера телефонов, почтовый адрес и адрес электронной почты. Я добился успеха в случае номера телефона и почтового адреса, но не электронной почты. я использую 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);
}
}
Но как сделать то же самое для электронной почты?
7 ответов
В документации 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 получил лучшее решение, несмотря на то, что мое решение является приемлемым, пожалуйста, прочитайте его ответ.
if(result.resultType == NSTextCheckingTypeLink)
{
if([result.URL.absoluteString rangeOfString:@"mailto:"].location != NSNotFound)
{
// email link
}
else
{
// url
}
}
Адрес электронной почты попадает в NSTextCheckingTypeLink. Просто найдите "mailto:" в найденном URL, и вы поймете, что это электронное письмо или URL.
Попробуйте следующий код, посмотрите, работает ли он у вас:
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"];
Вот чистая версия 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
Вот обновленная версия, совместимая с игровой площадкой, которая основана на ответе Дэйва Вуда и mkto:
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 = "test@mail.com"
isValid(email: email) // prints 'true'
email.isValidEmail // prints 'true'
Кажется, детектор теперь работает для электронной почты?
let types = [NSTextCheckingType.Link, NSTextCheckingType.PhoneNumber] as NSTextCheckingType
responseAttributedLabel.enabledTextCheckingTypes = types.rawValue
И я могу нажимать на электронные письма. Я использую TTTAttributedLabel, хотя.
Вот пример электронной почты в 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