验证器 (Validator)

Validator 是一个用 Swift 编写的用户输入验证库。它功能全面,设计可扩展,并且将 UI 留给您自行处理。

以下是如何验证电子邮件地址的示例:

let emailRule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError)
"invalid@email,com".validate(emailRule) // -> .invalid(validationError)

...或者验证用户是否年满 18 岁:

let eighteenYearsAgo = Date().addingTimeInterval(-568024668)
let drinkingAgeRule = ValidationRuleComparison<Date>(min: eighteenYearsAgo, error: validationError)
let dateOfBirth = Date().addingTimeInterval(-662695446) // 21 years old
dateOfBirth.validate(rule: rule) // -> .valid

...或者验证数字是否在指定范围内:

let numericRule = ValidationRuleComparison<Int>(min: 50, max: 100, error: validationError)
42.validate(numericRule) // -> .invalid(validationError)

...或者验证文本字段是否包含有效的 Visa 或 American Express 卡号:

let cardRule = ValidationRulePaymentCard(availableTypes: [.visa, .amex], error: validationError)
paymentCardTextField.validate(cardRule) // -> .valid or .invalid(validationError) depending on what's in paymentCardTextField

特性

演示 (Demo)

demo-vid

安装 (Installation)

CocoaPods

CocoaPods Compatible CocoaPods Compatible

pod 'Validator'

Carthage

Carthage Compatible

github "adamwaite/Validator"

用法 (Usage)

Validator 可以使用一个或多个 ValidationRule 验证任何 Validatable 类型。验证操作返回一个 ValidationResult,它要么匹配 .valid,要么匹配 .invalid([Error])

let rule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError)

let result = "invalid@email,com".validate(rule: rule)
// Note: the above is equivalent to Validator.validate(input: "invalid@email,com", rule: rule)

switch result {
case .valid: print("😀")
case .invalid(let failures): print(failures.first?.message)
}

验证规则 (Validation Rules)

必需 (Required)

验证类型是否存在 (非 nil)。

let stringRequiredRule = ValidationRuleRequired<String?>(error: validationError)

let floatRequiredRule = ValidationRuleRequired<Float?>(error: validationError)

注意 - 您不能在可选的 Validatable 类型上使用 validate (例如 myString?.validate(aRule...),因为可选链机制会绕过调用。"thing".validate(rule: aRule...) 可以正常工作。 要以这种方式验证可选类型是否必需,请使用:Validator.validate(input: anOptional, rule: aRule)

相等 (Equality)

验证一个 Equatable 类型是否等于另一个。

let staticEqualityRule = ValidationRuleEquality<String>(target: "hello", error: validationError)

let dynamicEqualityRule = ValidationRuleEquality<String>(dynamicTarget: { return textField.text ?? "" }, error: validationError)

比较 (Comparison)

根据最大值和最小值验证一个 Comparable 类型。

let comparisonRule = ValidationRuleComparison<Float>(min: 5, max: 7, error: validationError)

长度 (Length)

验证 String 长度是否满足最小值、最大值或范围。

let minLengthRule = ValidationRuleLength(min: 5, error: validationError)

let maxLengthRule = ValidationRuleLength(max: 5, error: validationError)

let rangeLengthRule = ValidationRuleLength(min: 5, max: 10, error: validationError)

模式 (Pattern)

根据模式验证 String

ValidationRulePattern 可以使用 String 模式或符合 ValidationPattern 的类型进行初始化。 Validator 在 Patterns 目录中提供了一些常用模式。

let emailRule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError)

let digitRule = ValidationRulePattern(pattern: ContainsNumberValidationPattern(), error: someValidationErrorType)

let helloRule = ValidationRulePattern(pattern: ".*hello.*", error: validationError)

包含 (Contains)

验证 Equatable 类型是否在预定义的 SequenceType 的元素中(其中 SequenceTypeElement 与输入类型匹配)。

let stringContainsRule = ValidationRuleContains<String, [String]>(sequence: ["hello", "hi", "hey"], error: validationError)

let rule = ValidationRuleContains<Int, [Int]>(sequence: [1, 2, 3], error: validationError)

URL

验证 String 是否是符合 RFC 2396 的有效 URL。

let urlRule = ValidationRuleURL(error: validationError)

支付卡 (Payment Card)

验证 String 是否是有效的支付卡号,首先通过 Luhn 校验算法 进行验证,然后确保其符合一些支付卡提供商的格式。

public enum PaymentCardType: Int {
    case amex, mastercard, visa, maestro, dinersClub, jcb, discover, unionPay
    ///...

要针对任何卡类型进行验证(仅 Luhn 校验)

let anyCardRule = ValidationRulePaymentCard(error: validationError)

要针对一组可接受的卡类型进行验证(例如本例中的 Visa、Mastercard 和 American Express)

let acceptedCardsRule = ValidationRulePaymentCard(acceptedTypes: [.visa, .mastercard, .amex], error: validationError)

条件 (Condition)

使用自定义条件验证 Validatable 类型。

let conditionRule = ValidationRuleCondition<[String]>(error: validationError) { $0.contains("Hello") }

创建您自己的规则 (Create Your Own)

通过遵循 ValidationRule 协议来创建您自己的验证规则

protocol ValidationRule {
    typealias InputType
    func validate(input: InputType) -> Bool
    var error: ValidationError { get }
}

示例 (Example)

struct HappyRule {
    typealias InputType = String
    var error: ValidationError
    func validate(input: String) -> Bool {
        return input == "😀"
    }
}

如果您的自定义规则尚未存在于库中,并且您认为它对其他人可能有用,那么如果您通过 pull request 将其添加进来,那就太好了。

多个验证规则 (ValidationRuleSet)

验证规则可以组合成 ValidationRuleSet,其中包含验证类型的规则集合。

var passwordRules = ValidationRuleSet<String>()

let minLengthRule = ValidationRuleLength(min: 5, error: validationError)
passwordRules.add(rule: minLengthRule)

let digitRule = ValidationRulePattern(pattern: .ContainsDigit, error: validationError)
passwordRules.add(rule: digitRule)

Validatable

任何符合 Validatable 协议的类型都可以使用 validate: 方法进行验证。

// Validate with a single rule:

let result = "some string".validate(rule: aRule)

// Validate with a collection of rules:

let result = 42.validate(rules: aRuleSet)

将类型扩展为 Validatable (Extend Types As Validatable)

扩展 Validatable 协议以使新类型可验证。

extension Thing : Validatable { }

注意:协议扩展中的实现应意味着您无需自己实现任何内容,除非您需要验证多个属性。

ValidationResult

validate: 方法返回 ValidationResult 枚举。 ValidationResult 可以采用以下两种形式之一

  1. .valid:输入满足验证规则。
  2. .invalid:输入未通过验证规则。 .invalid 结果具有一个关联的符合 ValidationError 的类型数组。

错误 (Errors)

使用任何 ValidationError 初始化规则,以便在验证失败时传递结果。

示例 (Example)

struct User: Validatable {

    let email: String

    enum ValidationErrors: String, ValidationError {
        case emailInvalid = "Email address is invalid"
        var message { return self.rawValue }
    }

    func validate() -> ValidationResult {
        let rule ValidationRulePattern(pattern: .emailAddress, error: ValidationErrors.emailInvalid)
        return email.validate(rule: rule)
    }
}

验证 UIKit 元素 (Validating UIKit Elements)

符合 ValidatableInterfaceElement 的 UIKit 元素可以使用 validate: 方法验证其输入。

let textField = UITextField()
textField.text = "I'm going to be validated"

let slider = UISlider()
slider.value = 0.3

// Validate with a single rule:

let result = textField.validate(rule: aRule)

// Validate with a collection of rules:

let result = slider.validate(rules: aRuleSet)

在输入更改时验证 (Validate On Input Change)

可以配置 ValidatableInterfaceElement 以在输入更改时自动验证,分为 3 个步骤。

  1. 附加一组默认规则

    let textField = UITextField()
    var rules = ValidationRuleSet<String>()
    rules.add(rule: someRule)
    textField.validationRules = rules
  2. 附加一个闭包以在输入更改时触发

    textField.validationHandler = { result in
      switch result {
      case .valid:
    	    print("valid!")
      case .invalid(let failureErrors):
    	    let messages = failureErrors.map { $0.message }
        print("invalid!", messages)
      }
    }
  3. 开始观察

    textField.validateOnInputChange(enabled: true)

注意 - 使用 .validateOnInputChange(enabled: false) 结束观察。

将 UI 元素扩展为 Validatable (Extend UI Elements As Validatable)

扩展 ValidatableInterfaceElement 协议以使界面元素可验证。

示例 (Example)

extension UITextField: ValidatableInterfaceElement {

    typealias InputType = String

    var inputValue: String { return text ?? "" }

    func validateOnInputChange(enabled: Bool) {
        switch validationEnabled {
        case true: addTarget(self, action: #selector(validateInputChange), forControlEvents: .editingChanged)
        case false: removeTarget(self, action: #selector(validateInputChange), forControlEvents: .editingChanged)
        }
    }

    @objc private func validateInputChange(_ sender: UITextField) {
        sender.validate()
    }

}

协议扩展中的实现应意味着您只需要实现:

  1. typealias:要验证的输入类型 (例如 UITextFieldString)。
  2. inputValue:要验证的输入值 (例如 UITextFieldtext 值)。
  3. validateOnInputChange: 方法:用于配置输入更改观察。

示例 (Examples)

此存储库中有一个示例项目。

贡献 (Contributing)

欢迎任何贡献和建议! 请确保任何新代码都包含单元测试,并且所有现有测试都通过。 请使用任何新功能更新 README。 谢谢!

联系方式 (Contact)

@adamwaite

许可证 (License)

特此授予任何人免费获得本软件及相关文档文件(“软件”)副本的许可,以不受限制地处理本软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售本软件的副本,并允许向其提供本软件的人员这样做,但须符合以下条件

以上版权声明和本许可声明应包含在所有副本或本软件的实质性部分中。

本软件按“原样”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性、特定用途适用性和非侵权性的保证。 在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼还是其他诉讼中,因本软件或本软件的使用或其他处理而产生或与之相关的责任。