Check password string strength criteria in Swift
update: Xcode 8.3.2 • Swift 3.1
enum PasswordError: String, Error {
case eightCharacters
case oneUppercase
case oneLowercase
case oneDecimalDigit
}
extension String {
func validatePassword() throws {
guard count > 7
else { throw PasswordError.eightCharacters }
guard rangeOfCharacter(from: .uppercaseLetters) != nil
else { throw PasswordError.oneUppercase }
guard rangeOfCharacter(from: .lowercaseLetters) != nil
else { throw PasswordError.oneLowercase }
guard rangeOfCharacter(from: .decimalDigits) != nil
else { throw PasswordError.oneDecimalDigit }
}
}
let myPass = "12345678"
do {
try myPass.validatePassword()
print("valid password action")
} catch let error as PasswordError {
print("Password error:", error)
switch error {
case .eightCharacters:
print("Needs At Least Eight Characters action")
case .oneUppercase:
print("Needs At Least one Uppercase action")
case .oneLowercase:
print("Needs At Least one Lowercase action")
case .oneDecimalDigit:
print("Needs At Least One DecimalDigit action")
}
} catch {
print("error:", error)
}
How to implement a regex for password validation in Swift?
The regex is
(?:(?:(?=.*?[0-9])(?=.*?[-!@#$%&*ˆ+=_])|(?:(?=.*?[0-9])|(?=.*?[A-Z])|(?=.*?[-!@#$%&*ˆ+=_])))|(?=.*?[a-z])(?=.*?[0-9])(?=.*?[-!@#$%&*ˆ+=_]))[A-Za-z0-9-!@#$%&*ˆ+=_]{6,15}
Use RegEx to validate a password on iOS Swift
The main issue is that NSPredicate
with MATCHES
requires the full string to match and consume the whole input. Lookarounds - you are using lookaheads - do not consume text, that is, the texts they match are not added to the match value and the regex index stays where it was before attempting to match a lookaround pattern.
The last two parts can be thus fixed this way:
func isPasswordHasNumberAndCharacter(password: String) -> Bool {
let passRegEx = "(?=[^a-z]*[a-z])[^0-9]*[0-9].*"
let passwordTest = NSPredicate(format: "SELF MATCHES %@", passRegEx)
return passwordTest.evaluate(with: password)
}
func isPasswordHasNumberAndCharacterSign(password: String) -> Bool {
let passWordRegEx = "[a-zA-Z0-9!@#$%^&*]+"
let passwordTest = NSPredicate(format: "SELF MATCHES %@", passWordRegEx)
return passwordTest.evaluate(with: password)
}
The first part is OK, though you do not need the ^
and $
anchors (as the whole string input must match the pattern). However, to check a string length you do not even need a regex: see Get the length of a String.
Note:
^(?=[^a-z]*[a-z])[^0-9]*[0-9].*\z
matches a string that contains at least one lowercase ASCII letter and at least one ASCII digit^[a-zA-Z0-9!@#$%^&*]+$
will match a string that only contains ASCII letters, digits and some specific symbols. If you inlude a-
make sure it is at the end. Escape both[
and]
if you need to add them, too.
If you want to combine all that into 1 regex you could use
let passRegEx = "(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!@#$%^&*]{8,}"
Or, if you are not using the regex with the NSPredicate
MATCHES
, with anchors:
let passRegEx = "\\A(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!@#$%^&*]{8,}\\z"
Password validation in UITextField in iOS
This is how I would do it. The validation should be done at the end when the user has typed in the password and not in between.I will not be using NSRegularExpression
.
-(void)textFieldDidEndEditing:(UITextField *)textField{
int numberofCharacters = 0;
BOOL lowerCaseLetter,upperCaseLetter,digit,specialCharacter = 0;
if([textField.text length] >= 10)
{
for (int i = 0; i < [textfield.text length]; i++)
{
unichar c = [textfield.text characterAtIndex:i];
if(!lowerCaseLetter)
{
lowerCaseLetter = [[NSCharacterSet lowercaseLetterCharacterSet] characterIsMember:c];
}
if(!upperCaseLetter)
{
upperCaseLetter = [[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:c];
}
if(!digit)
{
digit = [[NSCharacterSet decimalDigitCharacterSet] characterIsMember:c];
}
if(!specialCharacter)
{
specialCharacter = [[NSCharacterSet symbolCharacterSet] characterIsMember:c];
}
}
if(specialCharacter && digit && lowerCaseLetter && upperCaseLetter)
{
//do what u want
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Please Ensure that you have at least one lower case letter, one upper case letter, one digit and one special character"
delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Please Enter at least 10 password"
delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
}
}
Hope this helps...
Regex to validate password strength
You can do these checks using positive look ahead assertions:
^(?=.*[A-Z].*[A-Z])(?=.*[!@#$&*])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z].*[a-z]).{8}$
Rubular link
Explanation:
^ Start anchor
(?=.*[A-Z].*[A-Z]) Ensure string has two uppercase letters.
(?=.*[!@#$&*]) Ensure string has one special case letter.
(?=.*[0-9].*[0-9]) Ensure string has two digits.
(?=.*[a-z].*[a-z].*[a-z]) Ensure string has three lowercase letters.
.{8} Ensure string is of length 8.
$ End anchor.
Swift live text field checking for characters from multiple arrays
It's easier if you use Set
instead of Array
. Here's an example:
private let upperCaseAll = Set("ABCDEFGHIJKLMNOPQRSTUVWXYZ".characters)
private let lowerCaseAll = Set("abcdefghijklmnopqrstuvwxyz".characters)
private let numberAll = Set("0123456789".characters)
private let specialCharAll = Set("-/:;()$&@\".,?!'[]{}#%^\\|~<>€£¥".characters)
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Determines what the new value of the text field will be
let newText = range.length == 0 ? textField.text! + string : (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
// Turn that string into a Set of Characters
let characters = Set(newText.characters)
let hasUpperCase = !characters.intersect(self.upperCaseAll).isEmpty
let hasLowerCase = !characters.intersect(self.lowerCaseAll).isEmpty
let hasNumber = !characters.intersect(self.numberAll).isEmpty
let hasSpecialChar = !characters.intersect(self.specialCharAll).isEmpty
// Now turn your 4 other views to green/red as needed
print("hasUpperCase = \(hasUpperCase), hasLowercase = \(hasLowerCase), hasNumber = \(hasNumber), hasSpecialChar = \(hasSpecialChar)")
...
return true
}
Swift 5 - Error with the password validation regex
(?=^.{7,}$)(?=^.*[A-Z].*$)(?=^.*\d.*$).*
Short Explanation
(?=^.{7,}$)
At least 7 characters long(?=^.*[A-Z].*$)
At least one uppercase letter(?=^.*\d.*$)
At least one number.*
Match the string that contains all assertions
See the regex demo
Swift Example
let phonePattern = #"(?=^.{7,}$)(?=^.*[A-Z].*$)(?=^.*\d.*$).*"#
func isValid(password: String) -> Bool {
return password.range(
of: phonePattern,
options: .regularExpression
) != nil
}
print(isValid(password: "Pass1")) // false
print(isValid(password: "Pass23word")) // true
print(isValid(password: "23password")) // false
print(isValid(password: "Greatpass13")) // true
Related Topics
Append Text or Data to Text File in Swift
Sort Dictionary by Values in Swift
Making Buttons Appear and Disappear When Clicked
Nsdate() or Date() Shows the Wrong Time
How to Use String.Substringwithrange? (Or, How Do Ranges Work in Swift)
How to Get the Count of a Swift Enum
Why Is an Observedobject Array Not Updated in My Swiftui Application
How to Print the Type or Class of a Variable in Swift
Object X of Class Y Does Not Implement Methodsignatureforselector in Swift
Protocol Doesn't Conform to Itself
How Does String Substring Work in Swift
Load a Uiview from Nib in Swift
Read and Write a String from Text File
How to Use Swift 4 Codable in Core Data
What's the Cleanest Way of Applying Map() to a Dictionary in Swift