4

I use Regex for checking a password. But it is not working as intended. I use some Unit-tests to check the regex.

@implementation NSString (regexMatch)

- (BOOL)matchesRegex:(NSString *)regexPattern
{
    NSError *error = nil;

    NSRegularExpression* regex = [NSRegularExpression
                                  regularExpressionWithPattern:regexPattern 
                                  options:NSRegularExpressionSearch
                                  error:&error];

    if(error) 
    {
        NSLog(@"Error on maches regex: %@ on %@: %@", regex, self, error);
        return NO;
    }

    NSUInteger maches = [regex numberOfMatchesInString:self 
                                               options:NSRegularExpressionSearch 
                                                 range:NSMakeRange(0, [self length])];

    return (maches > 0);
}

@end

The Regex:

const static NSString *REGEX_VALID_PASS = @"(^((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[-_,.@#$%'\"]).{6,20})$)";

Unit tests:

//Password 
// At least:
//  - between 6 and 20 chars
//  - a capital character
//  - a small character
//  - a digit
//  - a special char: - _ , . @ # $ % ยด '
STAssertTrue([@"Pass1-" matchesRegex:REGEX_VALID_PASS], @"Password 1 failed");

STAssertTrue([@"aPrettyLongPassw0rd@" matchesRegex:REGEX_VALID_PASS], @"Password 2 failed");

STAssertTrue([@"Pw987321-_,.@#$%'`" matchesRegex:REGEX_VALID_PASS], @"Password 3 failed");

//Returns TRUE ???
STAssertFalse([@"password1@" matchesRegex:REGEX_VALID_PASS], @"Wrong password 4 works (No capital letter)");

//Returns TRUE ???
STAssertFalse([@"PASSWORD2#" matchesRegex:REGEX_VALID_PASS], @"Wrong password 5 works (No small letter)");

STAssertFalse([@"Password8" matchesRegex:REGEX_VALID_PASS], @"Wrong password 6 works (No special letter)");

STAssertFalse([@"Password$" matchesRegex:REGEX_VALID_PASS], @"Wrong password 7 works (No digit letter)");

STAssertFalse([@"PrettyLongPasswordIsWrong123#" matchesRegex:REGEX_VALID_PASS], @"Wrong password 8 works (> 20)");

STAssertFalse([@"Pw@3" matchesRegex:REGEX_VALID_PASS], @"Wrong password 9 works (< 6)");

Password 'password1@' and 'PASSWORD2#' are returning TRUE but there are not correct.

Errors:

file://localhost/Users/user/app/AppTest.m: error: testRegex (AppTest) failed: "[@"password1@" matchesRegex:REGEX_VALID_PASS]" should be false. Wrong password 4 works (No capital letter)

and


file://localhost/Users/user/app/AppTest.m: error: testRegex (AppTest) failed: "[@"PASSWORD2#" matchesRegex:REGEX_VALID_PASS]" should be false. Wrong password 5 works (No small letter)
Justin
  • 2,960
  • 2
  • 34
  • 48
  • 1
    Besides from your problem, you can remove some brackets, `^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[-_,.@#$%'\"]).{6,20}$` would do the same. โ€“ stema May 15 '12 at 09:47
  • Thanks, I know. I copied it from the server-side. I first wanted to get it working before I altered the Regex. But thank you for noticing. โ€“ Justin May 15 '12 at 10:19

1 Answers1

3

You specified NSRegularExpressionCaseInsensitive option, so it makes sense that the expression does not differentiate between upper and lower case letters.

With the NSRegularExpressionCaseInsensitive option specified, (?=.*[a-z]) will match any letter, including capital ones; similarly, (?=.*[A-Z]) will match lowercase letters as well.

Your failed unit tests expect a different behavior: both of them are checking that the password contains upper and lower case letters, while the input contains letters in the same case.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523