有人知道如何在Swift中验证电子邮件地址吗?我找到了这个代码:
- (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;
}
}
但我无法翻译成斯威夫特。
如果你正在寻找一个干净简单的解决方案,你应该看看https://github.com/nsagora/validation-components。
它包含一个电子邮件验证谓词,很容易集成在你的代码:
let email = "test@example.com"
let rule = EmailValidationPredicate()
let isValidEmail = rule.evaluate(with: email)
在引擎盖后面,它使用RFC 5322 regex (http://emailregex.com):
let regex = "(?:[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}" +
"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" +
"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\p{L}0-9](?:[a-" +
"z0-9-]*[\\p{L}0-9])?\\.)+[\\p{L}0-9](?:[\\p{L}0-9-]*[\\p{L}0-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]?|[\\p{L}0-9-]*[\\p{L}0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" +
"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
我建议使用它作为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
}
}
要使用它:
if "hodor@gameofthrones.com".isEmail { // true
print("Hold the Door")
}
Swift 5 -可伸缩的验证层
使用此层,您将轻松地在任何文本字段上获得惊人的验证。
只需遵循以下流程即可。
1. 添加这些枚举:
import Foundation
enum ValidatorType
{
case email
case name
// add more cases ...
}
enum ValidationError: Error, LocalizedError
{
case invalidUserName
case invalidEmail
// add more cases ...
var localizedDescription: String
{
switch self
{
case .invalidEmail:
return "Please kindly write a valid email"
case .invalidUserName:
return "Please kindly write a valid user name"
}
}
}
2. 将此功能添加到String:
extension String
{
// MARK:- Properties
var isValidEmail: 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)
}
// MARK:- Methods
func validatedText(_ validationType: ValidatorType) throws
{
switch validationType
{
case .name:
try validateUsername()
case .email:
try validateEmail()
}
}
// MARK:- Private Methods
private func validateUsername() throws
{
if isEmpty
{
throw ValidationError.invalidUserName
}
}
private func validateEmail() throws
{
if !isValidEmail
{
throw ValidationError.invalidEmail
}
// add more validations if you want like empty email
}
}
3.添加以下功能到UITextField:
import UIKit
extension UITextField
{
func validatedText(_ validationType: ValidatorType) throws
{
do
{
try text?.validatedText(validationType)
}
catch let validationError
{
shake()
throw validationError
}
}
// MARK:- Private Methods
private func shake()
{
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.1
animation.repeatCount = 5
animation.fromValue = NSValue(cgPoint: CGPoint(x: center.x + 6, y: center.y))
animation.toValue = NSValue(cgPoint: CGPoint(x: center.x - 6, y: center.y))
layer.add(animation, forKey: "position")
}
}
使用
import UIKit
class LoginVC: UIViewController
{
// MARK: Outlets
@IBOutlet weak var textFieldEmail: UITextField!
// MARK: View Controller Life Cycle
override func viewDidLoad()
{
super.viewDidLoad()
}
// MARK: Methods
private func checkEmail() -> Bool
{
do
{
try textFieldEmail.validatedText(.email)
}
catch let error
{
let validationError = error as! ValidationError
// show alert to user with: validationError.localizedDescription
return false
}
return true
}
// MARK: Actions
@IBAction func loginTapped(_ sender: UIButton)
{
if checkEmail()
{
let email = textFieldEmail.text!
// move safely ...
}
}
}
在Swift 5.7中,在Regex类的帮助下,我们可以以简单有效的方式验证电子邮件地址
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
}
我们还可以使用属性包装器来提高效率:
@propertyWrapper
struct EmailPropertyWrapper {
private var _value: String
var wrappedValue: String {
get { return isValidEmail(_value) ? _value : String() }
set { _value = newValue }
}
init(email: String) {
_value = email
}
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
}
}
struct User {
var name: String
@EmailPropertyWrapper var email: String
func validateProperty() -> Bool {
if name.isEmpty || email.isEmpty { return false }
return true
}
}
let user = User(name: "Sy", email: .init(email: "wwdc@icloud.com"))
print(user.validateProperty())
@JeffersonBe的答案是接近的,但如果字符串是“包含someone@something.com一个有效的电子邮件”,这不是我们想要的。下面是String上的一个扩展,它工作得很好(并且允许测试有效的phoneNumber和其他数据检测器来引导。
/// Helper for various data detector matches.
/// Returns `true` iff the `String` matches the data detector type for the complete string.
func matchesDataDetector(type: NSTextCheckingResult.CheckingType, scheme: String? = nil) -> Bool {
let dataDetector = try? NSDataDetector(types: type.rawValue)
guard let firstMatch = dataDetector?.firstMatch(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range: NSRange(location: 0, length: length)) else {
return false
}
return firstMatch.range.location != NSNotFound
// make sure the entire string is an email, not just contains an email
&& firstMatch.range.location == 0
&& firstMatch.range.length == length
// make sure the link type matches if link scheme
&& (type != .link || scheme == nil || firstMatch.url?.scheme == scheme)
}
/// `true` iff the `String` is an email address in the proper form.
var isEmail: Bool {
return matchesDataDetector(type: .link, scheme: "mailto")
}
/// `true` iff the `String` is a phone number in the proper form.
var isPhoneNumber: Bool {
return matchesDataDetector(type: .phoneNumber)
}
/// number of characters in the `String` (required for above).
var length: Int {
return self.characters.count
}