### Problem

Write a program to return True, if a string is a strong password.

A password is considered strong if below conditions are all met:

• It should have at least 6 characters and at most 20 characters.
• It must contain at least one lowercase, one uppercase and one digit.
• It must NOT contain three repeating characters in a row ("...aaa..." is weak, but "...aa...a..." is fine, assuming other conditions are met).

### Code

I've solved a similar problem to LeetCode Strong Password Checker. If you would like to review the code or add other methods or provide any change/improvement recommendations please do so! Thank you!

def strong_password_match(s: str) -> bool:
"""Returns a boolean if a password is correct"""
import re
if re.match(
r'^(?!.*([a-z])\1\1)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6,20}$', s) is not None: return True return False def strong_password_search(s: str) -> bool: """Returns a boolean if a password is correct""" import re if re.search( r'^(?!.*([a-z])\1\1)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6,20}$', s) is not None:
return True
return False

"""Returns a boolean if a password is correct"""
import re
if re.findall(
r'^(?!.*([a-z])\1\1)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6,20}$', s) != []: return True return False if __name__ == '__main__': # ---------------------------- TEST --------------------------- import timeit import cProfile DIVIDER_DASH_LINE = '-' * 50 GREEN_APPLE = '\U0001F34F' RED_APPLE = '\U0001F34E' test_methods = ( ("re.match", strong_password_match), ("re.search", strong_password_search), ("re.findall", strong_password_findall), ) test_inputs = ('abcAb1', 'abcAb1abcAb1abcAb100', 'abcAb1abcAb1abcAb10111', 'aaaAb1abcAb1abcAb100') # --------------------------------- PROFILING AND BANCHMARK SETTINGS -------------------------------------- NUMBER_OF_RUNS = 1 CPROFILING_ON = False BENCHMARK_ON = True for description, method in test_methods: print((GREEN_APPLE + RED_APPLE) * 5) for test_input in test_inputs: if CPROFILING_ON: print(f'{description} cProfiling: ', cProfile.run("method(test_input)")) if BENCHMARK_ON: print(f'{description} Benchmark: ', timeit.Timer( f'for i in range({NUMBER_OF_RUNS}): {method(test_input)}', 'gc.enable()').timeit()) if method(test_input): print(f'{GREEN_APPLE} {description}: "{test_input}" is a strong password.') else: print(f'{RED_APPLE} {description}: "{test_input}" is not a strong password.')  ### Output ππππππππππ re.match Benchmark: 1.8437564770000001 π re.match: "abcAb1" is a strong password. re.match Benchmark: 1.9900512190000006 π re.match: "abcAb1abcAb1abcAb100" is a strong password. re.match Benchmark: 1.782858269 π re.match: "abcAb1abcAb1abcAb10111" is not a strong password. re.match Benchmark: 1.8016775740000002 π re.match: "aaaAb1abcAb1abcAb100" is not a strong password. ππππππππππ re.search Benchmark: 1.8374795240000008 π re.search: "abcAb1" is a strong password. re.search Benchmark: 1.8352807049999988 π re.search: "abcAb1abcAb1abcAb100" is a strong password. re.search Benchmark: 1.8023251919999996 π re.search: "abcAb1abcAb1abcAb10111" is not a strong password. re.search Benchmark: 1.9213070860000006 π re.search: "aaaAb1abcAb1abcAb100" is not a strong password. ππππππππππ re.findall Benchmark: 1.7806425130000019 π re.findall: "abcAb1" is a strong password. re.findall Benchmark: 1.836686480000001 π re.findall: "abcAb1abcAb1abcAb100" is a strong password. re.findall Benchmark: 1.8053996060000017 π re.findall: "abcAb1abcAb1abcAb10111" is not a strong password. re.findall Benchmark: 1.8203372360000003 π re.findall: "aaaAb1abcAb1abcAb100" is not a strong password.  If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs. ### RegEx Circuit jex.im visualizes regular expressions: ### Source Strong Password Checker • ugh... I vehemently object to the LeetCode challenge for having a really crappy definition of "strong password". These are good guidelines.. Rules #1 and #2 actually make your passwords worse and less safe. Oct 25, 2019 at 8:00 ## 1 Answer # Imports I notice you import re three times, once for each password check function. Why? Just import the library once at the top of the file, and you can use it in all of your functions. # Returning Booleans Instead of returning True or False based on the result of the expression, simply return the expression. It results to a boolean anyway, so returning True and False is unnecessary; just return the expression. # DRY (Don't Repeat Yourself) You have three functions that essentially perform the same task, just with very slightly different function calls. You can compress these regex checks into one method. Then you can pass what type of check you want to perform on the password. See below. import re def strong_password_check(password: str, type_of_check: str) -> bool: """ Accepts a password and the type of check to perform on the password :param password: Password to check :param type_of_check: How to check the password. Has to be "match", "search", or "findall" """ regex = r'^(?!.*([a-z])\1\1)(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6,20}$'
if type_of_check == "match":
return re.match(regex, password) is not None
if type_of_check == "search":
return re.search(regex, password) is not None
if type_of_check == "findall":

Not really sure the usefulness of red and green apples. Again, importing cProfile and timeit should go at the top of the program.
I see you're checking for performance, but not for the actual strength of the password. Would your program agree that Password123 is a good password? Any security professional worth his salt wouldn't agree.