📜 ⬆️ ⬇️

Swift String Validating or simple validation of strings to meet criteria.

Good day to all. Today I want to talk about the problem of string validation in IOS projects. I think you, like me, often come across this when you need to check, for example, the password field for meeting several criteria.

For example:

- Password length is more than 6 characters
- At least one digit
- Upper and lower case letters
')
Often this requirement is implemented like this:

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

Simply. The function works, the password is checked. Everyone is happy.

Further, if we need to check the email field for correctness, we also write a function, for example:

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

And so on.

The growth of the project functions with such checks is becoming more and more. When creating a new project, we need to either start over or copy these functions from the previous project. Not very comfortable. One of the solutions under the cut.

At one point, I realized that it was time to solve this problem.

The obvious solution was to write your own Validator.

In truth, I did not invent anything new, such validators already exist and are easy to find on github. But the goal was to write exactly your own, perhaps better than the ones already presented.

The main tasks were:

- A universal way, to call from any place, we immediately get the result
- Easy setup, quickly specify the verification criteria
- Scalability.

The first step was to determine how we would create the criteria. A protocol was created for this:

  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 } 

To begin with, checks for Length, Registers were implemented. It looks like this:

LowercaseLetterExistCriteria
 public struct LowercaseLetterExistCriteria : Criteriable { public var debugErrorString: String = debugMessage(LowercaseLetterExistCriteria.self, message:"no lowercase char exists") public init(){} public func isonform(to value: String) -> Bool { for char in value.characters { if char.isLowercase() == true { 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 isonform(to value: String) -> Bool { let regExptest = NSPredicate(format: "SELF MATCHES %@", ".*[0-9]+.*") return regExptest.evaluate(with: value) } } 


UppercaseLetterExistCriteria
 public struct UppercaseLetterExistCriteria : Criteriable { public var debugErrorString: String = debugMessage(UppercaseLetterExistCriteria.self, message:"no uppercase char exists") public init(){} public func isonform(to value: String) -> Bool { for char in value.characters { if char.isUppercase() == true { return true } } return false } } 


Then the validator itself was implemented:

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 } } 


The validator is initialized with a set of criteria, a flag is set (to collect all the criteria that are not passed or to terminate when the first criterion is found) and a string is transmitted that will be validated. The result is an enumerated type:

 /// 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]) } 

Also for scalability you can easily define your own criteria:

 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 } } 

As a result, we got the functionality we need; we no longer need to produce functions. It is enough to define a set of criteria and check the string against them.

CocoaPod was also created where you can view all the source code.

Conclusion

In the future, there are plans to expand the functionality of the validator to instantly check the UITextField.
There is also an idea to extend the functionality to check not only strings, but any objects.

I hope this material will be useful.
Thanks for attention.

Source: https://habr.com/ru/post/316016/


All Articles