Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python password rules validation

Tags:

python

I'm practicing some Python and I'm having trouble understanding why this code won't take - function takes a string and if it's at least 10 characters in length, has at least 1 digit, 1 lowercase, and 1 uppercase letter, it should return True. Also, there's gotta be a more succinct way to write this than I did with all these nested conditionals. Thanks all!

import string
alphalower = string.ascii_lowercase
alphaupper = string.ascii_uppercase
digs = string.digits

def checkio(data):
    if len(data) >= 10:
        if data.count(digs) >= 1:
            if data.count(alphaupper) >= 1:
                if data.count(alphalower) >= 1:
                    return True
    else:
        return False
like image 608
SpicyClubSauce Avatar asked Apr 24 '15 20:04

SpicyClubSauce


People also ask

How do I check if a python password is strong or weak?

It must contain at least one lowercase letter, at least one uppercase letter, and at least one numeric character. It must not contain three repeating characters in a row like … aaa…, …

How does Python validate username and password?

import time complete = False user = [["username","password"],["username2","password2"]] while not complete: username = input("What is the username?") password = input("What is the password?") for n in len(user): if username == user[n][0]: print("Good!") if password == user[n][1]: print("User has been identified, ...

How do I check if a python username is valid?

valid_username(username) # if it isn't valid we should tell them why if not(result): print (reason) # otherwise the username is good - ask them for a password # get a password from the user password = input("Password: ") # determine if the password is valid pwresult, pwreason = uservalidation.

Is Python password acceptable?

Conditions for a valid password are: Should have at least one number. Should have at least one uppercase and one lowercase character. Should have at least one special symbol. Should be between 6 to 20 characters long.


4 Answers

The following should work, and removes the unnecessary imports :

def checkio(data):
    return len(data) >= 10 and any(char.isdigit() for char in data) and any(char.islower() for char in data) and any(char.isupper() for char in data)

You can iterate over strings by default, and each string has the isdigit, islower, etc... methods that you can use. The any() method returns True if any of the values returned by an iterable passed to it is true, and the something(value) for value in iterable syntax creates a generator expression, which iterates over each character of the string and checks whether it's a digit/lowercase/uppercase character.

Based on this answer.


Benchmark time, with my horrible benchmark code (but it seems to do the job) :

from time import time
import re

data = "ULFFunH8ni" # the password

def benchmark(method): # benchmark method, loops 1000000 times and prints how much it took
    start = time()
    for _ in range(1000000): method(data)
    print(time() - start)

def checkio_kasra(data): # Kasra's answer
    return len(data) >= 10 and all([any(i.isdigit() for i in data),any(i.islower() for i in data),any(i.isupper() for i in data)])

def checkio_andreysabitov(data): # Andrey Sabitov's regex-based answer
    if len(data) < 10:
        return False

    digital = re.compile('[0-9]+')
    capital = re.compile('[A-Z]+')
    lower = re.compile('[a-z]+')

    return (digital.search(data) is not None) and (capital.search(data) is not None)  and (lower.search(data) is not None)

def checkio_andredaniel(data): # My answer
    return len(data) >= 10 and any(char.isdigit() for char in data) and any(char.islower() for char in data) and any(char.isupper() for char in data)

def checkio_shashank_bitmask(data):
    if len(data) < 10: return False
    lud_bitmask = 0
    for ch in data:
        if ch.islower():
            lud_bitmask |= 4
            if lud_bitmask == 7: return True
        elif ch.isupper():
            lud_bitmask |= 2
            if lud_bitmask == 7: return True
        elif ch.isdigit():
            lud_bitmask |= 1
            if lud_bitmask == 7: return True
    return False

def checkio_shashank_pure_regex(data):
    return bool(re.match(r'(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[a-z]).{10}', data))

def checkio_shashank_impure_regex(data):
    return len(data) >= 10 and re.match(r'(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[a-z])', data)

benchmark(checkio_kasra)
benchmark(checkio_andreysabitov)
benchmark(checkio_andredaniel)
benchmark(checkio_shashank_bitmask)
benchmark(checkio_shashank_pure_regex)
benchmark(checkio_shashank_impure_regex)

The results, on my low-end tablet running Windows 7 and Python 3.4.x (ran it two times to be sure) :

$ python pass.py
6.333611011505127 # Shashank
9.625216960906982 # Kasra
11.450419902801514 # Andrey Sabitov
8.36161494255066 # Me

However, given a semi-incorrect input of 1XYZXYZXYZ (length and digits are good, but all uppercase), some solutions fail to stop early :

7.456813097000122 # Shashank
9.328815937042236 # Kasra
11.169620037078857 # Andrey Sabitov
6.349210977554321 # Me

Note that these benchmarks don't take into account eventual edits. I suggest you run the benchmark on your own machine using the latest answers. Feel free to update this post with new results.

like image 71
5 revs, 2 users 70%user2629998 Avatar answered Oct 19 '22 16:10

5 revs, 2 users 70%user2629998


import re    
def checkio(data):
    if len(data) < 10:
        return False

    digital = re.compile('[0-9]+')
    capital = re.compile('[A-Z]+')
    lower = re.compile('[a-z]+')

    return (digital.search(data) is not None) and (capital.search(data) is not None)  and (lower.search(data) is not None)
like image 23
Andrey Sabitov Avatar answered Oct 19 '22 14:10

Andrey Sabitov


You can use 3 generator expression with any function within all :

def checkio(data): 
    return len(data) >= 10 and all([any(i.isdigit() for i in data),any(i.islower() for i in data),any(i.isupper() for i in data)])   

Demo :

>>> checkio('1&*^&^%%gA')
True
>>> checkio('1&*^&^%%gf')
False
like image 1
Mazdak Avatar answered Oct 19 '22 15:10

Mazdak


One unique way of doing it would be to use a bitmask:

def checkio_shashank_bitmask(data):
    if len(data) < 10: return False
    lud_bitmask = 0
    for ch in data:
        if ch.islower():
            lud_bitmask |= 4
            if lud_bitmask == 7: return True
        elif ch.isupper():
            lud_bitmask |= 2
            if lud_bitmask == 7: return True
        elif ch.isdigit():
            lud_bitmask |= 1
            if lud_bitmask == 7: return True
    return False

print(checkio('5Hortpass')) # False
print(checkio('dumbpa55w0rd')) # False
print(checkio('DumbPassword')) # False
print(checkio('DumbPassword2015')) # True

This scales well for large inputs and stops as early as it can.


Here is what I think to be an optimized regex solution with non-greedy positive lookaheads that stops as soon as possible:

import re

def checkio_shashank_pure_regex(data):
    return bool(re.match(r'(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[a-z]).{10}', data))

However, I am not a regex expert, so if you have any optimization ideas, let me know.


From some further testing, I've determined that this is a bit faster and is probably the fastest solution so far for both correct and incorrect inputs at least with a highly optimized regex module:

def checkio_shashank_impure_regex(data):
    return len(data) >= 10 and re.match(r'(?=.*?[0-9])(?=.*?[A-Z])(?=.*?[a-z])', data)
like image 1
Shashank Avatar answered Oct 19 '22 14:10

Shashank