Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking strength of password with regex

Tags:

python

regex

The function is to find out how strong password is. It's considered strong if:

  1. length is greater than or equal to 10 characters
  2. it contains at least one digit
  3. at least one uppercase letter
  4. one lowercase letter
  5. the password may only contain ASCII latin letters or digits

Is there a way to reduce the amount of code in the function? Please help me make the code of function shorter than 200 characters (try to solve without assigning values to variables)

import re
def golf(password):
    if len(password) >=  10 \
    and re.search("^[a-zA-Z0-9]+", password) \
    and re.search("[a-z]+", password) \
    and re.search("[A-Z]+", password) \
    and re.search("[0-9]+", password):
        print(password, True)
        return True
    else:
        print(password, False)
        return False


if __name__ == '__main__':
    golf('A1213pokl') == False
    golf('bAse730onE') == True
    golf('asasasasasasasaas') == False
    golf('QWERTYqwerty') == False
    golf('123456123456') == False
    golf('QwErTy911poqqqq') == True
    golf('..........') == False
like image 438
user2978216 Avatar asked Nov 23 '17 07:11

user2978216


Video Answer


3 Answers

While you already have your answer, I'd even try to optimize the pattern. Instead of .* and then backtracking, I'd apply the principle of contrast directly:

(?=\D*\d)          # NOT a number, 0+ times, then one number
(?=[^A-Z]*[A-Z])   # NOT an UPPERCASE, 0+times, then an UPPERCASE
(?=[^a-z]*[a-z])   # same with lowercase
^[A-Za-z0-9]{10,}$ # allowed characters, 10+, with anchors on both sides

Condensed and demo:

(?=\D*\d)(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])[A-Za-z0-9]{10,}$

The idea here is, that while .* brings you down the line and then backtracks, the pattern above is likely to come to an end faster.


At last the Python snippet:
import re

def golf(password=None):
    rx = re.compile(r'(?=\D*\d)(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])[A-Za-z0-9]{10,}$')
    return True if rx.match(password) else False

passwords = ['A1213pokl', 'bAse730onE', 'asasasasasasasaas', 'QWERTYqwerty', '123456123456', 'QwErTy911poqqqq', '..........']
vectors = [golf(password) for password in passwords]
print(vectors)
# [False, True, False, False, False, True, False]
like image 151
Jan Avatar answered Oct 20 '22 22:10

Jan


The (not so :) stupid way:

from re import search as s
def golf(p):
    return all([len(p)>=10,s("^[a-zA-Z0-9]+",p),s("[a-z]+",p),s("[A-Z]+",p),s("[0-9]+",p)])

And BTW, you probably want some assert statements in your if __name__ == '__main__': block...

like image 35
Julien Avatar answered Oct 20 '22 22:10

Julien


This regex should do:

 (?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])^[a-zA-Z0-9]{10,}$
like image 1
perreal Avatar answered Oct 20 '22 21:10

perreal