-1

Im having some problems with the code below. I'm using PyCharm. The program is supposed to get an input for password of the user and check if it has at least 3 upper case chars and at least 3 numbers. The second task is what im having troubles with.

import sys


def num(s):
regex = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
for k in regex:
    if regex == s:
        print(y)
        y = y + 1
return y


passw = input("Enter password")
passw2 = list(passw)
lenght = (len(passw2))
if lenght < 8:
print("Password needs to be at least 8 chars long")
else:
    i = 0
    for x in passw2:
        if x.isupper():
            i += 1
if i < 3:
    print("You need at least 3 upper cased chars in your password")
    sys.exit()
else:
    numpassw2 = num(passw2)
    if numpassw2<3:
        print("At least 3 numbers needs to be given")
    else:
        print("OK,lets continue")

It gets stuck at calling out the num() function and gives following errors:

Traceback (most recent call last):
File "H:/szkola/python/projects/password/passwchecker.py", line 27, in <module>
numpassw2 = num(passw2)
File "H:/szkola/python/projects/password/passwchecker.py", line 10, in num
return y
UnboundLocalError: local variable 'y' referenced before assignment
TrebledJ
  • 8,713
  • 7
  • 26
  • 48
  • Hi there welcome to SO. Please check over the [formatting](https://meta.stackexchange.com/questions/22186/how-do-i-format-my-code-blocks) in [your question](https://stackoverflow.com/posts/53571189/edit) and ensure that it accurately reflects your real code. – TrebledJ Dec 01 '18 at 13:25
  • Some of your indents are off in the code you show here. This cannot run. – Jongware Dec 01 '18 at 13:36

4 Answers4

1

In your function num(s) declare a variable named y. Because of its missing in your function and it is raising an error.

def num(s):
    y = 0 # DECLARE y BEFORE CALL IT.
    regex = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
    for k in regex:
        for c in s:
            if c == k:
                print(y)
                y = y + 1
    return y
Alif Jahan
  • 793
  • 1
  • 7
  • 20
1

Your problem is the result of false scoping - the variable you want to use is not known. Learn more here: Short Description of the Scoping Rules?


You can use sum() over booleans - each True sums as 1. There are pre-build function for checking islower, isupper, isdigit - you can those like this:

def check_pw(p):
    # count how much of which type is in the password
    num_digit = sum(c.isdigit() for c in p) # True == 1, False == 0
    num_upper = sum(c.isupper() for c in p)
    num_lower = sum(c.islower() for c in p)

    # check if all categories are at least 3 times in it 
    ok =  all(x >= 3 for x in [num_digit, num_lower, num_upper])

    # do some output / error handling 
    print("Numbers: {}".format(num_digit), 
          "UPPERS:  {}".format(num_upper),
          "lowers:  {}".format(num_lower))
    print(p, " is Ok: ", ok) 

    # return if ok or not - if not the calling code has to ask/check a new password
    return ok

for p in [ "no", "NO", "StillNo", "ABCdef12no", "YESyes123"]: 
    check_pw(p)  # not using the return value here

Output:

Numbers: 0 UPPERS:  0 lowers:  2
no  is Ok:  False

Numbers: 0 UPPERS:  2 lowers:  0
NO  is Ok:  False

Numbers: 0 UPPERS:  2 lowers:  5
StillNo  is Ok:  False

Numbers: 2 UPPERS:  3 lowers:  5
ABCdef12no  is Ok:  False

Numbers: 3 UPPERS:  3 lowers:  3
YESyes123  is Ok:  True

Doku:

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
0

Try to change the code to something like this:

import sys


def num(s):
    y = 0
    regex = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
    for k in regex:
        for l in s:
            if regex == l:
                print(y)
                y += 1
    return y


passw = input("Enter password")
passw2 = list(passw)
lenght = (len(passw2))
if lenght < 8:
    print("Password needs to be at least 8 chars long")
else:
    i = 0
    for x in passw2:
        if x.isupper():
            i += 1
    if i < 3:
        print("You need at least 3 upper cased chars in your 
             password")
        sys.exit()
    else:
        numpassw2 = num(passw2)
        if numpassw2<3:
            print("At least 3 numbers needs to be given")
        else:
            print("OK,lets continue")
samuq
  • 306
  • 6
  • 16
0

Here's an other option:

MIN_LENGTH = 8
MIN_UPPER = 3
MIN_DIGIT = 3


def check_pass(p):
    if not p or len(p) < MIN_LENGTH:
        return False # fast-exit, validate length 
    count_upper = count_digit = 0
    pass_upper = pass_digit = False
    for char in p: # iterate over the characters
        if char.isupper():
            count_upper += 1 # increment the counter and check if we've reached the limit
            pass_upper = count_upper >= MIN_UPPER
        elif char.isdigit():
            count_digit += 1 # increment the counter and check if we've reached the limit
            pass_digit = count_digit >= MIN_DIGIT
        else: # for any other character we have nothing to do
            continue 
        # we got here because the caracter was a digit or an upper, meaning that 1 of the counters has changed and maybe the "pass" flags also 
        if pass_upper and pass_digit:
            # we've passed the checks, so fast-exit we don't need to iterate anymore
            return True
    # if we've got here, it means that the password didn't passed the checks 
    return False

I think it's better as it has fewer iterations and has "fast-exits"

Lohmar ASHAR
  • 1,639
  • 14
  • 18