Software Engineering

How to Validate Passwords with Regex in Python


The challenge

You need to write regex that will validate a password to make sure it meets the following criteria:

  • At least six characters long
  • contains a lowercase letter
  • contains an uppercase letter
  • contains a number

Valid passwords will only be alphanumeric characters.

The solution in Python code

Option 1:

from re import compile, VERBOSE

regex = compile("""
^              # begin word
(?=.*?[a-z])   # at least one lowercase letter
(?=.*?[A-Z])   # at least one uppercase letter
(?=.*?[0-9])   # at least one number
[A-Za-z\d]     # only alphanumeric
{6,}           # at least 6 characters long
$              # end word
""", VERBOSE)

Option 2:

import re
regex = re.compile(r"""
    (?=^[a-zA-Z0-9]{6,}$)
    (?=\w*[a-z])
    (?=\w*[A-Z])
    (?=\w*\d)
""", re.X)

Option 3:

regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^\W_]{6,}$"

Test cases to validate our solution

from re import search
test.describe("Basic tests")
test.assert_equals(bool(search(regex, 'fjd3IR9')), True)
test.assert_equals(bool(search(regex, 'ghdfj32')), False)
test.assert_equals(bool(search(regex, 'DSJKHD23')), False)
test.assert_equals(bool(search(regex, 'dsF43')), False)
test.assert_equals(bool(search(regex, '4fdg5Fj3')), True)
test.assert_equals(bool(search(regex, 'DHSJdhjsU')), False)
test.assert_equals(bool(search(regex, 'fjd3IR9.;')), False)
test.assert_equals(bool(search(regex, 'fjd3  IR9')), False)
test.assert_equals(bool(search(regex, 'djI38D55')), True)
test.assert_equals(bool(search(regex, 'a2.d412')), False)
test.assert_equals(bool(search(regex, 'JHD5FJ53')), False)
test.assert_equals(bool(search(regex, '!fdjn345')), False)
test.assert_equals(bool(search(regex, 'jfkdfj3j')), False)
test.assert_equals(bool(search(regex, '123')), False)
test.assert_equals(bool(search(regex, 'abc')), False)
test.assert_equals(bool(search(regex, '123abcABC')), True)
test.assert_equals(bool(search(regex, 'ABC123abc')), True)
test.assert_equals(bool(search(regex, 'Password123')), True)

test.describe("Random tests")
from random import random, randint
sol=r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{6,}$"
lower="abcdefghijklmnopqrstuvwxyz"
upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
digits="0123456789"
all="".join([lower,upper,digits])
wrong=" !_+-?/\\"

for _ in range(100):
  s="".join(sorted([upper[randint(0,len(upper)-1)], lower[randint(0,len(lower)-1)], digits[randint(0,len(digits)-1)]]+[all[randint(0,len(all)-1)] if randint(0,10) else wrong[randint(0,len(wrong)-1)] for q in range(randint(0,15))], key=lambda a: random()))
  test.it("Testing for "+repr(s))
  test.assert_equals(search(regex,s)!=None, search(sol,s)!=None, "It should work for random inputs too")