Задача на тему "Ветвления" в Python
Необходимо написать программу для проверки пароля на безопасность, в данном случае необходимо соблюсти хотя бы три критерия:
- Длина пароля не менее 5 символов
- Содержит буквы латинского алфавита как в верхнем, так и в нижнем регистре
- Хотя бы одну цифру от 0 до 9
- Хотя бы один спец.символ: "@,#,%,&
Сначала было задание написать эту программу без конструкции ветвления, соблюдая при этом все 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 шт):
Идея с множествами интересная, но я бы поменял на 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('Пароль недостаточно сложный')
А мне вариант с проверкой через множества нравится. Но я бы написал в функциональном стиле, без списковых сокращений. Ну и сами множества ведь можно гораздо короче записать. Да и переменные с условиями не нужны, нужна только их коллекция:
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('Пароль недостаточно сложный')
Новый вариант Пообщавшись с 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