giorgionocera
giorgionocera

Reputation: 6556

How to validate an e-mail address in Swift?

Does anyone know how to validate an e-mail address in Swift? I found this code:

- (BOOL) validEmail:(NSString*) emailString {

    if([emailString length]==0){
        return NO;
    }

    NSString *regExPattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";

    NSRegularExpression *regEx = [[NSRegularExpression alloc] initWithPattern:regExPattern options:NSRegularExpressionCaseInsensitive error:nil];
    NSUInteger regExMatches = [regEx numberOfMatchesInString:emailString options:0 range:NSMakeRange(0, [emailString length])];

    NSLog(@"%i", regExMatches);
    if (regExMatches == 0) {
        return NO;
    } else {
        return YES;
    }
}

but I can't translate it to Swift.

Upvotes: 427

Views: 296980

Answers (30)

SomuYadav
SomuYadav

Reputation: 123

In Swift 5.7, with the help of the Regex class, we can validate email addresses in a simple and efficient manner
        private func isValidEmail(_ email: String) -> Bool {
              guard let emailRegex = try? Regex("[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}")  
              else { return false }
              return email.firstMatch(of: emailRegex) != nil
           }
Also we can use a property wrapper to make it more efficient:
    import Foundation
    
    @propertyWrapper
    struct ValidEmail {
        var wrappedValue: String {
            didSet {
                if !isValidEmail(wrappedValue) {
                    wrappedValue = ""
                }
            }
        }
        
        init(wrappedValue: String) {
            if isValidEmail(wrappedValue) {
                self.wrappedValue = wrappedValue
            } else {
                self.wrappedValue = ""
            }
        }
        
        private func isValidEmail(_ email: String) -> Bool {
            let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
            let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
            return emailTest.evaluate(with: email)
        }
    }
    // Usage:
    
    struct User {
        var name: String
        @ValidEmail var email: String
    }
    
    var user = User(name: "John Doe", email: "[email protected]")
    print(user.email) // Prints: [email protected]
    
    user.email = "invalid email"
    print(user.email) // Prints: ""

Upvotes: 1

Alejandro Iván
Alejandro Iván

Reputation: 4051

EDIT: Updated to make the NSPredicate global.

This a new version for "THE REASONABLE SOLUTION" by @Fattie, tested on Swift 4.1 in a new file called String+Email.swift:

import Foundation

extension String {
    private static let __firstpart = "[A-Z0-9a-z]([A-Z0-9a-z._%+-]{0,30}[A-Z0-9a-z])?"
    private static let __serverpart = "([A-Z0-9a-z]([A-Z0-9a-z-]{0,30}[A-Z0-9a-z])?\\.){1,5}"
    private static let __emailRegex = __firstpart + "@" + __serverpart + "[A-Za-z]{2,6}"
    private static let __predicate = NSPredicate(format: "SELF MATCHES %@", __emailRegex)

    public var isEmail: Bool {
        return Self.predicate.evaluate(with: self)
    }
}

So its usage is simple:

let str = "[email protected]"
if str.isEmail {
    print("\(str) is a valid e-mail address")
} else {
    print("\(str) is not a valid e-mail address")
}

I simply don't like to add a func to the String objects, as being an e-mail address is inherent to them (or not). So a Bool property would fit better than a func, from my understanding.

Upvotes: 7

George Haidenko
George Haidenko

Reputation: 76

Two simple extensions:

extension NSRegularExpression {
  convenience init(_ pattern: String) {
    do {
      try self.init(pattern: pattern)
    } catch {
      preconditionFailure("Illegal regular expression: \(pattern).")
    }
  }

  func wholeMatch(_ string: String) -> Bool {
    let range = NSRange(location: 0, length: string.utf16.count)
    guard let match = firstMatch(in: string, options: [], range: range) else { return false }
    return range.length == match.range.length
  }
}

extension String {
  var isValidEmail: Bool {
    let __firstpart = "[A-Z0-9a-z]([A-Z0-9a-z._%+-]{0,30}[A-Z0-9a-z])?"
    let __serverpart = "([A-Z0-9a-z]([A-Z0-9a-z-]{0,30}[A-Z0-9a-z])?\\.){1,5}"
    let pattern = __firstpart + "@" + __serverpart + "[A-Za-z]{2,20}"
    let regex = NSRegularExpression(pattern)
    return regex.wholeMatch(self)
  }
}

Why am I doing it?) Despite the huge number of answers, I have not found a suitable one for me. Therefore, I made up my answer, collecting all the best.

So, I used a pretty good regex from Fattie's answer. A small improvement is only in the length of the top-level domain (among the currently registered ones, the length is 18 characters.) And the second and main reason is incorrect processing of special characters like № and ™ by NSPredicate. It seems that such characters are not processed according to unicode, but rather according to similar graphemes. For example, № is recognized as "No". NSRegularExpression lacks this drawback.

Yes, I do not take into account emails that are not in English. And I have not found clear information on why it is worth putting NSRegularExpression in the global. But you can adjust appropriately)

Upvotes: 0

Nicolas Manzini
Nicolas Manzini

Reputation: 8546

Here is a fuse of the two most up-voted answer with a basic correct enough regex: a String extension using predicate so you can call string.isEmail

    extension String {
        var isEmail: Bool {
           let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,20}"            
           let emailTest  = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
           return emailTest.evaluateWithObject(self)
        }
    }

Upvotes: 34

Nathan Hosselton
Nathan Hosselton

Reputation: 1315

Apple's own documentation for the RegexBuilder type (introduced in Swift 5.7) now offers an example of minimal email validation, complete with named component capture.

(Copying here for posterity as they sometimes change their examples)

let word = OneOrMore(.word)
let emailPattern = Regex {
    Capture {
        ZeroOrMore {
            word
            "."
        }
        word
    }
    "@"
    Capture {
        word
        OneOrMore {
            "."
            word
        }
    }
}

let text = "My email is [email protected]."
if let match = text.firstMatch(of: emailPattern) {
    let (wholeMatch, name, domain) = match.output
    // wholeMatch is "[email protected]"
    // name is "my.name"
    // domain is "example.com"
}

Despite this question already having too many answers, I felt this was worth sharing since it:

  1. Uses the latest Swift APIs
  2. Does not overcomplicate the regex logic (a trap for email validation)
  3. Comes directly from Apple (almost like they knew)

Upvotes: 4

Fattie
Fattie

Reputation: 12582

(Preamble. Be aware that in some cases, you can now use this solution built-in to iOS: https://multithreaded.stitchfix.com/blog/2016/11/02/email-validation-swift/ )


The only solution:

1 - it avoids the horrific regex mistakes often seen in example code

2 - it does NOT allow ridiculous emails such as "x@x"

(If for some reason you need a solution that allows nonsense strings such as 'x@x', use another solution.)

3 - the code is extremely understandable

4 - it is KISS, reliable, and tested to destruction on commercial apps with enormous numbers of users

5 - the predicate is a global, as Apple says it must be

let __firstpart = "[A-Z0-9a-z]([A-Z0-9a-z._%+-]{0,30}[A-Z0-9a-z])?"
let __serverpart = "([A-Z0-9a-z]([A-Z0-9a-z-]{0,30}[A-Z0-9a-z])?\\.){1,5}"
let __emailRegex = __firstpart + "@" + __serverpart + "[A-Za-z]{2,8}"
let __emailPredicate = NSPredicate(format: "SELF MATCHES %@", __emailRegex)

extension String {
    func isEmail() -> Bool {
        return __emailPredicate.evaluate(with: self)
    }
}

extension UITextField {
    func isEmail() -> Bool {
        return self.text?.isEmail() ?? false
    }
}

It's that easy.

Explanation for anyone new to regex:

In this description, "OC" means ordinary character - a letter or a digit.

__firstpart ... has to start and end with an OC. For the characters in the middle you can have certain characters such as underscore, but the start and end have to be an OC. (However, it's ok to have only one OC and that's it, for example: [email protected])

__serverpart ... You have sections like "blah." which repeat. (Example, mail.city.fcu.edu.) The sections have to start and end with an OC, but in the middle you can also have a dash "-". It's OK to have a section which is just one OC. (Example, w.campus.edu) You can have up to five sections, you have to have one. Finally the TLD (such as .com) is strictly 2 to 8 in size . (Obviously, just change the "8" as preferred by your support department.)


IMPORTANT !

You MUST keep the predicate as a global, do not build it every time.

Note that this is the first thing Apple mentions about the whole issue in the docs.

Suggestions which do not cache the predicate are non-starters.


Non-english alphabets

Naturally, if you deal with non-english alphabets, adjust appropriately.

Upvotes: 75

Hassaan Fayyaz
Hassaan Fayyaz

Reputation: 209

Majority of the above regex examples fail to catch error when there are even basic problems with emails. For example

  1. [email protected] - consecutive dots
  2. [email protected] - dot after @
  3. [email protected] - dot before @
  4. [email protected] - starts with a dot

Here is a string extension I have used that uses regex with tighter rules.

extension String {
    func isValidEmail() -> Bool {
        let emailRegEx = "^(?!\\.)([A-Z0-9a-z_%+-]?[\\.]?[A-Z0-9a-z_%+-])+@[A-Za-z0-9-]{1,20}(\\.[A-Za-z0-9]{1,15}){0,10}\\.[A-Za-z]{2,20}$"
        let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: self)
   }
}

Here is how we can write test case for it.

XCTAssertFalse("[email protected]".isValidEmail())
XCTAssertTrue("[email protected]".isValidEmail())

Upvotes: 2

zaph
zaph

Reputation: 112857

Here is a method based on rangeOfString:

class func isValidEmail(testStr:String) -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let range = testStr.rangeOfString(emailRegEx, options:.RegularExpressionSearch)
    return range != nil
}

Note: updated TLD length.

Here is the definitive RegEx for email as per RFC 5322, note that this is best not used because it only checks the basic syntax of email addresses and does not check is the top level domain exists.

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*
  |  "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]
      |  \\[\x01-\x09\x0b\x0c\x0e-\x7f])*")
@ (?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
  |  \[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
       (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:
          (?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]
          |  \\[\x01-\x09\x0b\x0c\x0e-\x7f])+)
     \])

See Regular-Expressions.info for more complete information on email RegExs.

Note that no escaping as required by a language such as Objective-C or Swift.

Upvotes: 9

Jano
Jano

Reputation: 63667

Make a simple test for a @ and . and send a confirmation email.

Consider this:

  • Half of the world uses non-ASCII characters.
  • Regexes are slow and complex. Btw check at least for char/letter/Unicode range, not az.
  • You can’t afford full validation because RFC rules and corresponding regex are too complex.

I’m using this basic check:

// similar to https://softwareengineering.stackexchange.com/a/78372/22077
import Foundation

/**
 Checks that
 - length is 254 or less (see https://stackoverflow.com/a/574698/412916)
 - there is a @ which is not the first character
 - there is a . after the @
 - there are at least 4 characters after the @
*/
func isValidEmail(email: String) -> Bool {
    guard email.count <= 254 else { 
        return false 
    }
    let pos = email.lastIndex(of: "@") ?? email.endIndex
    return (pos != email.startIndex)
        && ((email.lastIndex(of: ".") ?? email.startIndex) > pos) 
        && (email[pos...].count > 4)
}

print(isValidEmail(email: "アシッシュ@ビジネス.コム")) // true

Note that

  • It is considerably faster than regex and NSDataDetector.

  • It correctly reports the following as valid:

Håkan.Söderström@malmö.se"
[email protected]"
试@例子.测试.مثال.آزمایشی"
[email protected]"
[email protected]
  • It incorrectly reports the following as invalid –because they are actually valid but likely the product of a user error:
a @ b
a@b

Related:

Upvotes: 8

Fero
Fero

Reputation: 676

Here's an up to date playground compatible version that uses the standard library so you don't have to maintain a regex:

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'

Upvotes: 1

Ken Mueller
Ken Mueller

Reputation: 4163

Simplest way in Swift 5

extension String {
    var isValidEmail: Bool {
        NSPredicate(format: "SELF MATCHES %@", "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}").evaluate(with: self)
    }
}

Example

"[email protected]".isValidEmail

returns...

true

Upvotes: 39

ami rt
ami rt

Reputation: 933

Perfect Regex like Google Email

"^[A-Z0-9a-z][a-zA-Z0-9_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"

Upvotes: -1

Maxim Shoustin
Maxim Shoustin

Reputation: 77904

I would use NSPredicate:

func isValidEmail(_ email: String) -> Bool {        
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"

    let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
    return emailPred.evaluate(with: email)
}

for versions of Swift earlier than 3.0:

func isValidEmail(email: String) -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"

    let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
    return emailPred.evaluate(with: email)
}

for versions of Swift earlier than 1.2:

func isValidEmail(email: String) -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"

    if let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx) {
        return emailPred.evaluateWithObject(email)
    }
    return false
}

Upvotes: 900

M A Russel
M A Russel

Reputation: 1557

Swift 5

 func isValidEmailAddress(emailAddressString: String) -> Bool {

 var returnValue = true
 let emailRegEx = "[A-Z0-9a-z.-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,3}"

 do {
        let regex = try NSRegularExpression(pattern: emailRegEx)
        let nsString = emailAddressString as NSString
        let results = regex.matches(in: emailAddressString, range: NSRange(location: 0, length: nsString.length))

        if results.count == 0
        {
            returnValue = false
        }

    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        returnValue = false
    }

    return  returnValue
}

Then:

let validEmail = isValidEmailAddress(emailAddressString: "[email protected]")
print(validEmail)

Upvotes: -2

Suran
Suran

Reputation: 1227

For anyone who is still looking for an answer to this, please have a look at the following framework;

ATGValidator

It is a rule based validation framework, which handles most of the validations out of box. And top it all, it has form validator which supports validation of multiple textfields at the same time.

For validating an email string, use the following;

"[email protected]".satisfyAll(rules: [StringRegexRule.email]).status

If you want to validate an email from textfield, try below code;

textfield.validationRules = [StringRegexRule.email]
textfield.validationHandler = { result in
    // This block will be executed with relevant result whenever validation is done.
    print(result.status, result.errors)
}
// Below line is to manually trigger validation.
textfield.validateTextField()

If you want to validate it while typing in textfield or when focus is changed to another field, add one of the following lines;

textfield.validateOnInputChange(true)
// or
textfield.validateOnFocusLoss(true)

Please check the readme file at the link for more use cases.

Upvotes: -1

ikbal
ikbal

Reputation: 1250

Use of Swift 4.2

extension String {
    func isValidEmail() -> Bool {
        let regex = try? NSRegularExpression(pattern: "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$", options: .caseInsensitive)
        return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.count)) != nil
    }
    func isValidName() -> Bool{
        let regex = try? NSRegularExpression(pattern: "^[\\p{L}\\.]{2,30}(?: [\\p{L}\\.]{2,30}){0,2}$", options: .caseInsensitive)

        return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.count)) != nil
    } }

And used

if (textField.text?.isValidEmail())! 
    {
      // bla bla
    }
else 
    {

    }

Upvotes: 5

JaneDoe
JaneDoe

Reputation: 462

Here is a very simple way available in current Swiftmailer. Most of the other answers are old and reinvent the wheel.

As per Swiftmailer documentation: https://swiftmailer.symfony.com/docs/messages.html#quick-reference

use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\RFCValidation;

$validator = new EmailValidator();
$validator->isValid("[email protected]", new RFCValidation()); //true

This is by far the simplest and most robust approach, imo. Just install via Composer the Egulias\EmailValidator library which should already be brought in as a dependency of SwiftMailer anyway.

Upvotes: -3

Naresh
Naresh

Reputation: 17882

In Swift 4.2 and Xcode 10.1

//Email validation
func isValidEmail(email: String) -> Bool {
    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
    var valid = NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: email)
    if valid {
        valid = !email.contains("Invalid email id")
    }
    return valid
}

//Use like this....
let emailTrimmedString = emailTF.text?.trimmingCharacters(in: .whitespaces)
if isValidEmail(email: emailTrimmedString!) == false {
   SharedClass.sharedInstance.alert(view: self, title: "", message: "Please enter valid email")
}

If you want to use SharedClass.

//This is SharedClass
import UIKit
class SharedClass: NSObject {

static let sharedInstance = SharedClass()

//Email validation
func isValidEmail(email: String) -> Bool {
    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
    var valid = NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: email)
    if valid {
        valid = !email.contains("Invalid email id")
    }
    return valid
}

private override init() {

}
}

And call function like this....

if SharedClass.sharedInstance. isValidEmail(email: emailTrimmedString!) == false {
   SharedClass.sharedInstance.alert(view: self, title: "", message: "Please enter correct email")
   //Your code here
} else {
   //Code here
}

Upvotes: 1

JeffersonBe
JeffersonBe

Reputation: 569

I would suggest using it as an extension of String:

extension String {    
    public var isEmail: Bool {
        let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)

        let firstMatch = dataDetector?.firstMatch(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range: NSRange(location: 0, length: length))

        return (firstMatch?.range.location != NSNotFound && firstMatch?.url?.scheme == "mailto")
    }

    public var length: Int {
        return self.characters.count
    }
}

And to use it:

if "[email protected]".isEmail { // true
    print("Hold the Door")
}

Upvotes: 25

JavaBeast
JavaBeast

Reputation: 836

I improved @Azik answer. I allow more special characters which are allowed by guidelines, as well as return a few extra edge cases as invalid.

The group think going on here to only allow ._%+- in the local part is not correct per guidelines. See @Anton Gogolev answer on this question or see below:

The local-part of the email address may use any of these ASCII characters:

  • uppercase and lowercase Latin letters A to Z and a to z;

  • digits 0 to 9;

  • special characters !#$%&'*+-/=?^_`{|}~;

  • dot ., provided that it is not the first or last character unless quoted, and provided also that it does not appear consecutively unless quoted (e.g. [email protected] is not allowed but "John..Doe"@example.com is allowed);

  • space and "(),:;<>@[\] characters are allowed with restrictions (they are only allowed inside a quoted string, as described in the paragraph below, and in addition, a backslash or double-quote must be preceded by a backslash); comments are allowed

  • with parentheses at either end of the local-part; e.g. john.smith(comment)@example.com and (comment)[email protected] are both equivalent to [email protected];

The code I use will not allow restricted out of place special characters, but will allow many more options than the majority of answers here. I would prefer more relaxed validation to error on the side of caution.

if enteredText.contains("..") || enteredText.contains("@@") 
   || enteredText.hasPrefix(".") || enteredText.hasSuffix(".con"){
       return false
}

let emailFormat = "[A-Z0-9a-z.!#$%&'*+-/=?^_`{|}~]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)     
return emailPredicate.evaluate(with: enteredText)

Upvotes: 1

siva kumar
siva kumar

Reputation: 2915

I like to create extension

   extension String {

func isValidateEmail() -> Bool {
    let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)
    return emailPredicate.evaluate(with: self)
}

}

usage:

if emailid.text!.isValidateEmail() == false(){
 //do what ever you want if string is not matched.

}

Upvotes: -2

Abdelahad Darwish
Abdelahad Darwish

Reputation: 6067

Best solution with best result for

Swift 4.x

 extension String {

        func validateAsEmail() -> Bool {
            let emailRegEx = "(?:[a-zA-Z0-9!#$%\\&‘*+/=?\\^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%\\&'*+/=?\\^_`{|}" +
                "~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" +
                "x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-" +
                "z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5" +
                "]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-" +
                "9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" +
            "-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"

            let emailTest = NSPredicate(format:"SELF MATCHES[c] %@", emailRegEx)
            return emailTest.evaluate(with: self)
        }
    }

Upvotes: 1

Arsonik
Arsonik

Reputation: 2316

As a String class extension

SWIFT 4

extension String {
    func isValidEmail() -> Bool {
        // here, `try!` will always succeed because the pattern is valid
        let regex = try! NSRegularExpression(pattern: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$", options: .caseInsensitive)
        return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: count)) != nil
    }
}

Usage

if "rdfsdsfsdfsd".isValidEmail() {

}

Upvotes: 119

Maciej Chrzastek
Maciej Chrzastek

Reputation: 1490

Or you can have extension for optional text of UITextField:

how to use:

if  emailTextField.text.isEmailValid() {
      print("email is valid")
}else{
      print("wrong email address")
}

extension:

extension Optional where Wrapped == String {
    func isEmailValid() -> Bool{
        guard let email = self else { return false }
        let emailPattern = "[A-Za-z-0-9.-_]+@[A-Za-z0-9]+\\.[A-Za-z]{2,3}"
        do{
            let regex = try NSRegularExpression(pattern: emailPattern, options: .caseInsensitive)
            let foundPatters = regex.numberOfMatches(in: email, options: .anchored, range: NSRange(location: 0, length: email.count))
            if foundPatters > 0 {
                return true
            }
        }catch{
            //error
        }
        return false
    }
}

Upvotes: -1

Gefilte Fish
Gefilte Fish

Reputation: 1738

Here is an extension in Swift 3

extension String {
    func isValidEmail() -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self)
    }
}

Just use it like this:

if yourEmailString.isValidEmail() {
    //code for valid email address
} else {
    //code for not valid email address
}

Upvotes: 1

Bartłomiej Semańczyk
Bartłomiej Semańczyk

Reputation: 61774

Create simple extension:

extension NSRegularExpression {

    convenience init(pattern: String) {
        try! self.init(pattern: pattern, options: [])
    }
}

extension String {

    var isValidEmail: Bool {
        return isMatching(expression: NSRegularExpression(pattern: "^[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$"))
    }

    //MARK: - Private

    private func isMatching(expression: NSRegularExpression) -> Bool {
        return expression.numberOfMatches(in: self, range: NSRange(location: 0, length: characters.count)) > 0
    }
}

Example:

"[email protected]".isValidEmail //true
"b@bb".isValidEmail //false

You can extend following extension to anything you need: isValidPhoneNumber, isValidPassword etc...

Upvotes: 2

Nazik
Nazik

Reputation: 8434

Editing, updated for Swift 3:

func validateEmail(enteredEmail:String) -> Bool {

    let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)
    return emailPredicate.evaluate(with: enteredEmail)

}

Original answer for Swift 2:

func validateEmail(enteredEmail:String) -> Bool {

    let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)
    return emailPredicate.evaluateWithObject(enteredEmail)

}

It's working fine.

Upvotes: 121

Marlon Ruiz
Marlon Ruiz

Reputation: 1842

I prefer use an extension for that. Besides, this url http://emailregex.com can help you to test if regex is correct. In fact, the site offers differents implementations for some programming languages. I share my implementation for Swift 3.

extension String {
    func validateEmail() -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self)
    }
}

Upvotes: 7

Andrei Popa
Andrei Popa

Reputation: 169

My only addition to the list of responses would be that for Linux, NSRegularExpression does not exist, it's actually RegularExpression

    func isEmail() -> Bool {

    let patternNormal = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"

    #if os(Linux)
        let regex = try? RegularExpression(pattern: patternNormal, options: .caseInsensitive)
    #else
        let regex = try? NSRegularExpression(pattern: patternNormal, options: .caseInsensitive)
    #endif

    return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.characters.count)) != nil

This compiles successfully on both macOS & Ubuntu.

Upvotes: 1

Dani Pralea
Dani Pralea

Reputation: 4551

And for Swift 3:

extension String {
    func isValidEmail() -> Bool {
        let regex = try? NSRegularExpression(pattern: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$", options: .caseInsensitive)
        return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.characters.count)) != nil
    }
}

Upvotes: 0

Related Questions