Skip to content

Instantly share code, notes, and snippets.

@louisdh
Created May 22, 2017 18:16
Show Gist options
  • Save louisdh/2eb2cfb2bfb56e9c7993d0eca4a84a47 to your computer and use it in GitHub Desktop.
Save louisdh/2eb2cfb2bfb56e9c7993d0eca4a84a47 to your computer and use it in GitHub Desktop.
Email validation using NSDataDetector
import Foundation
// Adapted from https://www.cocoanetics.com/2014/06/e-mail-validation/
extension String {
var isValidEmail: Bool {
guard !self.characters.isEmpty else {
return false
}
let entireRange = NSRange(location: 0, length: self.characters.count)
let types: NSTextCheckingResult.CheckingType = [.link]
guard let detector = try? NSDataDetector(types: types.rawValue) else {
return false
}
let matches = detector.matches(in: self, options: [], range: entireRange)
// should only have a single match
guard matches.count == 1 else {
return false
}
guard let result = matches.first else {
return false
}
// result should be a link
guard result.resultType == .link else {
return false
}
// result should be a recognized mail address
guard result.url?.scheme == "mailto" else {
return false
}
// match must be entire string
guard NSEqualRanges(result.range, entireRange) else {
return false
}
// but schould not have the mail URL scheme
if self.hasPrefix("mailto:") {
return false
}
// no complaints, string is valid email address
return true
}
}
@acalism
Copy link

acalism commented Jun 11, 2020

if the string is "MAILTO:[email protected]", then the scheme is "MAILTO", instead of "mailto",
result.url?.scheme.lowercased == "mailto" will be better.

@EvgenyKarkan
Copy link

EvgenyKarkan commented Apr 21, 2024

Swift 5

extension String {

    var isValidEmail: Bool {

        guard !isEmpty else {
            return false
        }

        let entireRange = NSRange(location: 0, length: count)

        let types: NSTextCheckingResult.CheckingType = [.link]

        guard let detector = try? NSDataDetector(types: types.rawValue) else {
            return false
        }

        let matches = detector.matches(in: self, options: [], range: entireRange)

        // should only have a single match
        guard matches.count == 1 else {
            return false
        }

        guard let result = matches.first else {
            return false
        }

        // result should be a link
        guard result.resultType == .link else {
            return false
        }

        // result should be a recognized mail address
        guard result.url?.scheme == "mailto" else {
            return false
        }

        // match must be entire string
        guard NSEqualRanges(result.range, entireRange) else {
            return false
        }

        // but schould not have the mail URL scheme
        if hasPrefix("mailto:") {
            return false
        }

        // no complaints, string is valid email address
        return true
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment