Swift String Validating или простая валидация строк на соответсвие критериям

от автора

Всем доброго времени суток. Сегодня хочется поговорить про проблему валидации строк в IOS проектах. Думаю Вы как и я часто с этим сталкиваетесь, когда надо проверить, например, поле пароля на соответствие нескольким критериям.

Например:

— Длина пароля больше 6 символов
— Минимум одна цифра
— Буквы верхнего и нижнего регистра

Зачастую такое требование реализовываются примерно так:

    func isPasswordCorrect(_ value:String) -> Bool {         // code for check length, number exist, uppercase and lowercase chars     }

Просто. Функция работает, пароль проверяется. Все довольны.

Дальше если нам надо проверить поле email на корректность, мы также пишем функцию, например:

    func isEmailCorrect(_ value:String) -> Bool {         // code for check length, number exist, uppercase and lowercase chars     }

И так далее.

По росту проекта функций с такими проверками становится все больше и больше. При создании нового проекта нам надо или начинать все сначала или копировать эти функции с прошлого проекта. Не очень удобно. Один из вариантов решения под катом.

В один момент я понял что пора решать эту проблему.

Очевидным решением было написать свой Валидатор.

По правде, ничего нового я не придумывал, подобные валидаторы уже существую и их легко найти на github. Но цель была написать именно свой, возможно лучше чем уже представленые

Главными задачами были:

— Универсальный способ, вызывать с любого места, тут же получаем результат
— Легкая настройка, быстро указываем критерии проверки
— Масштабируемость.

Первым шагом было определить как мы будет создавать критерии. Для этого был создан протокол:

 public protocol Criteriable {     /// debug string for debug description of problem     var debugErrorString : String {get}          /// Check if value conform to criteria     ///     /// - Parameter value: value to be checked     /// - Returns: return true if conform     func isConform(to value:String) -> Bool } 

Для начала были реализованы проверки на Длину, Регистры. Выглядит это примерно так:

LowercaseLetterExistCriteria

 public struct LowercaseLetterExistCriteria : Criteriable {     public var debugErrorString: String = debugMessage(LowercaseLetterExistCriteria.self, message:"no lowwercase char exist")          public init(){}      public func isСonform(to value: String)  -> Bool {         for char in value.characters {             if String(char).lowercased() == String(char) && Int(String(char)) == nil {                 return true             }         }         return false     } } 

NumberExistCriteria

 public struct NumberExistCriteria : Criteriable {     public var debugErrorString: String = debugMessage(NumberExistCriteria.self, message:"no number char exist")          public init(){}      public func isСonform(to value: String) -> Bool {         for char in value.characters {             if let _ = Int(String(char)) {                 return true             }         }         return false     } } 

UppercaseLetterExistCriteria

 public struct UppercaseLetterExistCriteria : Criteriable {     public var debugErrorString: String = debugMessage(UppercaseLetterExistCriteria.self, message:"no uppercase char exist")          public init(){}          public func isСonform(to value: String) -> Bool {         for char in value.characters {             if String(char).uppercased() == String(char) && Int(String(char)) == nil {                 return true             }         }         return false     } } 

Затем был реализован сам валидатор:

StringValidator

 /// Validator public struct StringValidator  {     /// predictions     public var criterias: [Criteriable]          ///init     public init(_ criterias: [Criteriable]) {         self.criterias = criterias     }          /// validate redictors to comform     ///     /// - Parameters:     ///   - value: string than must be validate     ///   - forceExit: if true -> stop process when first validation fail. else create array of fail criterias     ///   - result: result of validating     public func isValide(_ value:String, forceExit:Bool, result:@escaping  (ValidatorResult) -> ()) {       // validating code     } } 

Валидатор инициализируется набором критериев, устанавливается флаг (собирать все критерии которые не пройдены или обрываться при первом найденом критерии) и передается строка которая будет отвалидирована. Результатом получаем перечисляемый тип:

 /// Validator result object /// /// - valid: everething if ok /// - notValid: find not valid criteria /// - notValide: not valid  array of criterias public enum ValidatorResult {     case valid     case notValid(criteria:Criteriable)     case notValides(criterias:[Criteriable]) } 

Также для масштабируемости легко можно определить собственный критерий:

 struct MyCustomCriteria : Criteriable {     var debugErrorString: String = debugMessage(MyCustomCriteria.self, message:"some debug message")     func isConform(to value: String) -> Bool {         /* some logic for check */         return false     } } 

В итоге мы получили нужный нам функционал, не нужно больше плодить функции. Достаточно определить набор критериев и проверять строку по ним.

Так же был создан CocoaPod.

Заключение

В будущем есть планы расширить функционал валидатора на моментальную проверку UITextField.
Так же есть идея расширить функционал на проверку не только строк, а любых обьектов.

Надеюсь данный материал будет полезен.
Спасибо за внимание.
ссылка на оригинал статьи https://habrahabr.ru/post/316016/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *