15

I have 1 UITextfield for password in my iPhone application.

I want to validate this textfield with the following validation.

  • Must be at least 10 characters
  • Must contain at least one lower case letter, one upper case letter, one digit and one special character
  • Valid special characters are – @#$%^&+=^.*(?=.{10,})(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$

How can I restrict the UITextField with above requirements?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
ChandreshKanetiya
  • 2,414
  • 5
  • 27
  • 41

11 Answers11

27

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

Paras Joshi
  • 20,427
  • 11
  • 57
  • 70
lakshmen
  • 28,346
  • 66
  • 178
  • 276
18

You can also do this by using Regex. Here are few example I am providing for you:

// *** Validation for Password ***

    // "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$" --> (Minimum 8 characters at least 1 Alphabet and 1 Number)
    // "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[$@$!%*#?&])[A-Za-z\\d$@$!%*#?&]{8,16}$" --> (Minimum 8 and Maximum 16 characters at least 1 Alphabet, 1 Number and 1 Special Character)
    // "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$" --> (Minimum 8 characters at least 1 Uppercase Alphabet, 1 Lowercase Alphabet and 1 Number)
    // "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}" --> (Minimum 8 characters at least 1 Uppercase Alphabet, 1 Lowercase Alphabet, 1 Number and 1 Special Character)
    // "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,10}" --> (Minimum 8 and Maximum 10 characters at least 1 Uppercase Alphabet, 1 Lowercase Alphabet, 1 Number and 1 Special Character)

Fourth from the list is your case, following code snippet shows how to use it:

-(BOOL)isValidPassword:(NSString *)passwordString
{
    NSString *stricterFilterString = @"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{10,}";
    NSPredicate *passwordTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", stricterFilterString];
    return [passwordTest evaluateWithObject:passwordString];
}

Using the method:

if(![self isValidPassword:txtPassword.text]) {
    /* Show alert: "Password must be minimum 10 characters,
       at least 1 Uppercase Alphabet, 1 Lowercase Alphabet, 
       1 Number and 1 Special Character" */
}
else {
    // Password is valid
}
martinjbaker
  • 1,424
  • 15
  • 23
NSPratik
  • 4,714
  • 7
  • 51
  • 81
14

Condition: Password should contain atleast 8 characters, 1 uppercase and 1 number

Solution in Swift 3

you can write String Extension like this,

extension String {
    func isValidPassword() -> Bool {
        let regularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}"
        let passwordValidation = NSPredicate.init(format: "SELF MATCHES %@", regularExpression)

        return passwordValidation.evaluate(with: self)
    }
}

//Example 1

var password = "@Abcdef011" //string from UITextField (Password)
password.isValidPassword() // -> true

//Example 2

var password = "Abcdef011" //string from UITextField 
password.isValidPassword() // -> false

or you can write function like this,

func validate(password: String) -> Bool
{
    let regularExpression = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}"

    let passwordValidation = NSPredicate.init(format: "SELF MATCHES %@", regularExpression)

    return passwordValidation.evaluate(with: password)
}

this will give you the same result.

7

Swift 3

check if password is strong ?

  1. length more than or equal 8
  2. lowercase
  3. uppercase
  4. decimal Digits
  5. special characters like !@#$%^&*()_-+ is optional

    Why i not use regular expression ?

    Because it's difficult to support reserved characters in regular expression syntax.


 func isValidated(_ password: String) -> Bool {
     var lowerCaseLetter: Bool = false
     var upperCaseLetter: Bool = false
     var digit: Bool = false
     var specialCharacter: Bool = false

     if password.characters.count  >= 8 {
         for char in password.unicodeScalars {
             if !lowerCaseLetter {
                 lowerCaseLetter = CharacterSet.lowercaseLetters.contains(char)
             }
             if !upperCaseLetter {
                 upperCaseLetter = CharacterSet.uppercaseLetters.contains(char)
             }
             if !digit {
                 digit = CharacterSet.decimalDigits.contains(char)
             }
             if !specialCharacter {
                 specialCharacter = CharacterSet.punctuationCharacters.contains(char)
             }
         }
         if specialCharacter || (digit && lowerCaseLetter && upperCaseLetter) {
             //do what u want
             return true
         }
         else {
             return false
         }
     }
     return false
 }
 let isVaildPass:Bool = isValidated("Test**00+-")
 print(isVaildPass)
Rob
  • 26,989
  • 16
  • 82
  • 98
dimohamdy
  • 2,917
  • 30
  • 28
5

You can verify your password validation using the below function just pass a password string and this will return you BOOL value.

-(BOOL) isPasswordValid:(NSString *)pwd {

    NSCharacterSet *upperCaseChars = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLKMNOPQRSTUVWXYZ"];
    NSCharacterSet *lowerCaseChars = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyz"];

    //NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];

    if ( [pwd length]<6 || [pwd length]>20 )
        return NO;  // too long or too short
    NSRange rang;
    rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
    if ( !rang.length )
        return NO;  // no letter
    rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]];
    if ( !rang.length )
        return NO;  // no number;
    rang = [pwd rangeOfCharacterFromSet:upperCaseChars];
     if ( !rang.length )
         return NO;  // no uppercase letter;
    rang = [pwd rangeOfCharacterFromSet:lowerCaseChars];
    if ( !rang.length )
        return NO;  // no lowerCase Chars;
    return YES;
}
Piyush Dubey
  • 2,416
  • 1
  • 24
  • 39
Akhtar
  • 3,172
  • 5
  • 19
  • 21
4

for me Best way was to use NSPredicate and regex. this is regex for your case: ^(?=.{10,})(?=.*[0-9])(?=.*[a-zA-Z])([@#$%^&=a-zA-Z0-9_-]+)$

image created on debuggex.com

objective C code:

NSString *regex = @"^(?=.{10,})(?=.*[0-9])(?=.*[a-zA-Z])([@#$%^&=a-zA-Z0-9_-]+)$";

NSPredicate *passwordTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];

BOOL isValid = [passwordTest evaluateWithObject:yourTextfield.text];
Viral Savaj
  • 3,379
  • 1
  • 26
  • 39
user3206558
  • 392
  • 1
  • 12
2

use a regex (NSRegularExpression class has docs on how to write the patten itself) and then :

- (BOOL)textField:(UITextField *)theTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    //delete
    if (string.length == 0) {
        return YES;
    }

    if (self.regEx) {
        NSMutableString* check = [NSMutableString stringWithString:theTextField.text];
        [check replaceCharactersInRange:range withString:string];
        NSTextCheckingResult* match = [self.regEx firstMatchInString:check options:0 range:NSMakeRange(0, [check length])];
        if (match.range.length != check.length) {
            return NO;
        }
    }
}

Warning: Restricting the input this way is really confusing for users. You type and type and the character you type just doesnt appear!

I'd maybe go with a small red (!) next to the test field but I'd always allow the input itself!

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • 2
    "Restricting the input this way is really confusing for users." -- particularly in a hidden password field! – iluvcapra Mar 01 '13 at 07:15
2

I have this elegant solution for Forms (like sign-up) where you have a lot of validation

I have in my custom UITextField the outlet:

@IBInspectable var regexpValidation: String? = nil

In storyboard I can access it through attribute inspector and put regexp string like that (for email):

[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?

then in my subclass I have this computed var:

@IBInspectable var regexpValidation: String? = nil // Optional, Set this in InterfaceBuilder

var inputIsValid: Bool {
    get {
        if let expr = regexpValidation {
           return (text.rangeOfString(expr, options: NSStringCompareOptions.RegularExpressionSearch, range: nil, locale: nil) != nil)
        } else {
            return true
        }

    }
}

which could be used like this:

   override func resignFirstResponder() -> Bool {
        if (inputIsValid) {
            return super.resignFirstResponder()
        }
        else {
            text = ""
            return false
        }
    }
Eugene Braginets
  • 856
  • 6
  • 16
1

You need to write your validation code in this delegate method of UITextField

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

Few links that you might want to refer for implementation

how to use regular expression in iOS sdk

iOS TextField Validation

Community
  • 1
  • 1
Baby Groot
  • 4,637
  • 39
  • 52
  • 71
1

Use the control:isValidObject: method of the NSTextFieldDelegate protocol which allows you to validate the value of a NSTextField. Assuming you have all your interface builder bits and pieces configured correctly, you might do something like this:

@interface PreferencesController : NSWindowController <NSTextFieldDelegate> {
    IBOutlet NSTextField *username, *password;
}

@end

@implementation PreferencesController

- (BOOL)control:(NSControl *)control isValidObject:(id)object
{
    if (control == password) {
      // Perform validation and return YES or NO
    }

    return YES;
}

@end
Tim Potter
  • 2,437
  • 21
  • 31
  • isn't this fired AFTER input? He wants to restrict the input.... IF it is called bore, this is cool :) – Daij-Djan Feb 28 '13 at 10:00
  • 1
    It is indeed fired after the input. I didn't read the question as restricting the key presses during input. That would be really confusing for the user, I think. – Tim Potter Feb 28 '13 at 10:13
  • it is confusing - and I speak from experience :D ill add that to my answer – Daij-Djan Feb 28 '13 at 10:36
1

SWIFT 5 USING RXSWIFT, a better, neat and reactive approach.

validate password function will be like this, Obviously you can add as many conditions as you want as per your requirement.

 func validatePassword(password: String) -> (Bool, String) {
  //Minimum 8 characters at least 1 Alphabet and 1 Number:
var tuple: (Bool, String) = (true, "")
var string = "Requires atleast"

if(password.rangeOfCharacter(from: CharacterSet.letters) == nil){
    string = "uppercase"
    tuple = (false, string)

}
if(password.rangeOfCharacter(from: CharacterSet.decimalDigits) == nil){
    string += ", number"
       tuple = (false, string)

   }
if(password.count < 8 ){
    string += ", 8 chars"
       tuple = (false, string)

   }
return tuple }


 func isPasswordValid(in string: String) -> Observable<(Bool, String)> {
    return Observable.create { observer -> Disposable in

        let tuple = self.validation.validatePasswordForSymbol(password: string)

        observer.onNext(tuple)


        return Disposables.create()
    }
}

You can use aforementioned function in viewModel or VC as per your architecture. Then invoke the same function like below in your VC.

passwordTextField.rx.text
            .orEmpty //1
            .filter { $0.count >= 1 } //2
            .flatMap { self.isPasswordValid(in: $0) }
            .subscribe(onNext: { result in
                print("Valid password", result)
                //update UI here 
                // result will be like (false, "Requires atleast, 8 chars, number")
            }).disposed(by: disposeBag)
Tabish Sohail
  • 1,040
  • 2
  • 9
  • 22