Задача на тему "Ветвления" в Python

Необходимо написать программу для проверки пароля на безопасность, в данном случае необходимо соблюсти хотя бы три критерия:

  1. Длина пароля не менее 5 символов
  2. Содержит буквы латинского алфавита как в верхнем, так и в нижнем регистре
  3. Хотя бы одну цифру от 0 до 9
  4. Хотя бы один спец.символ: "@,#,%,&

Сначала было задание написать эту программу без конструкции ветвления, соблюдая при этом все 4 условия, потом с ветвлениями - все это удалось решить. Но при условии, что необходимо соблюсти не все условия, а 3 и более произошел затык..Необходимо учитывать, что с циклами я еще не знакома

Мой код:

password = '12345%'

cond1 = len(password) >= 5  # длина пароля
cond2 = not password.islower() and not password.isupper()  # нижний и верхний регистр
cond3 = len({"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"} & set(password)) > 0  # цифры от 0 до 9
cond4 = len({'@', '#', '%', '&'} & set(password)) > 0  # содержит хотя бы один спец.символ


if len({cond1, cond2, cond3, cond4} & set(password)) >= 3:
    print("Пароль достаточно сложный")

else:
    print('Пароль недостаточно сложный')

Выводит без синтаксических ошибок, но логически неверные ответы


Ответы (3 шт):

Автор решения: gil9red

Идея с множествами интересная, но я бы поменял на any.

А для подсчета количества факторов можно использовать сложение, т.к. True можно представить как 1, а False как 0

Пример:

password = 'a0123B'

cond1 = len(password) >= 5
cond2 = any(c.islower() for c in password) and any(c.isupper() for c in password)
cond3 = any(x in password for x in "1234567890")
cond4 = any(x in password for x in "@#%&")

if cond1 + cond2 + cond3 + cond4 >= 3:
    print("Пароль достаточно сложный")
else:
    print('Пароль недостаточно сложный')

Вариант проверки большинства условий в одном цикле:

cond1 = len(password) >= 5
cond2_1 = cond2_2 = cond3 = cond4 = False

for c in password:
    if not cond2_1 and c.islower():
        cond2_1 = True
    if not cond2_2 and c.isupper():
        cond2_2 = True
    if not cond3 and c.isdigit():
        cond3 = True
    if not cond4 and c in "@#%&":
        cond4 = True

cond2 = cond2_1 and cond2_2

if cond1 + cond2 + cond3 + cond4 >= 3:
    print("Пароль достаточно сложный")
else:
    print('Пароль недостаточно сложный')
→ Ссылка
Автор решения: CrazyElf

А мне вариант с проверкой через множества нравится. Но я бы написал в функциональном стиле, без списковых сокращений. Ну и сами множества ведь можно гораздо короче записать. Да и переменные с условиями не нужны, нужна только их коллекция:

password = '1aA#'

conditions = (
    len(password) >= 5,
    any(map(str.islower, password)) and any(map(str.isupper, password)),
    set(password) & set("1234567890"),
    set(password) & set("@#%&"),
)

if sum(map(bool, conditions)) >= 3:
    print("Пароль достаточно сложный")
else:
    print('Пароль недостаточно сложный')
→ Ссылка
Автор решения: Andy Pavlov

Новый вариант Пообщавшись с CrazyElf, решил поменять свой вариант на представленный ниже.

Учитывая, что все условие сводится к определению длины пароля и наличию каждого типа включения, то все сводится к четырем условиям-генераторам, которые должны отработать всего один раз.

def password_check(password: str, min_cond: int = 3, min_lenght: int = 5):
    lower = next(filter(str.islower, password), 0)
    upper = next(filter(str.isupper, password), 0)
    nums = next(filter(str.isdigit, password), 0)
    special = next((p for p in password if p in '@#%&'), 0)
    return sum(map(bool, [lower, upper, nums, special, len(password) > min_lenght])) >= min_cond

Старый вариант Выше варианты красивые, но по мне можно все сделать несколько иначе, пройдясь по паролю за один раз.

Делаем словарь условий в виде диапазонов символов в Unicode для нижнего регистра, верхнего, цифр и спецсимволов со значением для каждого ключа 0.

Далее берем номер символа и сравниваем его с номером таблицы в Unicode через ord() по словарю. В какой диапазон (нижний регистр, верхний, цифры, спецсимволы) попали, туда в ключе со значениями меняем 0 на 1.

Дальше проверка длины пароля и общего условия по количеству символов по группам с сопоставлением с необходимым числом выполнения условий.

def password_check(password: str, min_cond: int = 3, min_lenght: int = 5):
    conditions = {(ord('A'), ord('Z')): 0, (ord('a'), ord('z')): 0, (ord('0'), ord('9')): 0, (ord('%'), ord('&'), ord('@'), ord('#')): 0}
    for p in password:
        n = ord(p)
        for c in conditions:
            if not conditions[c] and any([c[0] < n < c[1], n in c]):
                conditions[c] = 1
    return sum([len(password) >= min_lenght, *conditions.values()]) >= min_cond

print(password_check('1aA#'))  # True
print(password_check('aaaaaaaa'))  # False
print(password_check('AAAAAaaa'))  # True
print(password_check('aBs15#'))  # True
→ Ссылка