Проверка пароля по правилам

Применяем lookahead, чтобы проверить несколько независимых требований одним паттерном.

Каждое правило пароля — это отдельный lookahead (?=.*...), проверяющий наличие нужного символа где-то в строке.

Постановка задачи

Типичные требования к паролю: не короче 8 символов, есть хотя бы одна строчная буква, хотя бы одна заглавная и хотя бы одна цифра. Эти условия независимы, а порядок символов любой. Описать это одним «линейным» паттерном сложно — но lookahead решает задачу элегантно.

Подход «в лоб»: несколько проверок

Сначала — понятный вариант: проверяем каждое правило отдельной регуляркой. Это читаемо и легко расширяется:

import re

def check(pw):
    if len(pw) < 8:
        return False
    if not re.search(r"[a-z]", pw):
        return False
    if not re.search(r"[A-Z]", pw):
        return False
    if not re.search(r"\d", pw):
        return False
    return True

for pw in ["abc", "Abcdef12", "abcdef12", "ABCDEF12"]:
    print(pw, check(pw))

Вывод:

abc False
Abcdef12 True
abcdef12 False
ABCDEF12 False

Видно: Abcdef12 прошёл (есть всё), abcdef12 — нет (нет заглавной), ABCDEF12 — нет (нет строчной).

Подход одним паттерном: цепочка lookahead

Те же правила собираются в один паттерн через серию lookahead в начале. Каждый (?=.*X) требует: «где-то впереди есть X», не сдвигая позицию:

import re

pattern = re.compile(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$")

for pw in ["Abcdef12", "abcdef12", "Ab1", "Password123"]:
    print(pw, bool(pattern.match(pw)))

Вывод:

Abcdef12 True
abcdef12 False
Ab1 False
Password123 True

Разберём паттерн ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$ по частям:

  • ^ — начало строки; все проверки стартуют отсюда.
  • (?=.*[a-z]) — где-то есть строчная буква.
  • (?=.*[A-Z]) — где-то есть заглавная.
  • (?=.*\d) — где-то есть цифра.
  • .{8,}$ — и при этом длина не меньше 8 до конца строки.

Все lookahead проверяются из одной точки (начала), поэтому порядок символов в пароле не важен — каждое условие смотрит на всю строку независимо.

Что выбрать

Паттерн компактен, но «магичен». Для одного места он хорош; если правил много и они меняются, читаемее держать их отдельными проверками в коде. Регулярка-валидатор — мощный инструмент, но не всегда самый поддерживаемый.

Итог

  • Несколько независимых требований удобно проверять цепочкой lookahead из начала строки.
  • (?=.*X) означает «где-то впереди есть X», не двигая позицию.
  • Альтернатива — отдельные проверки в коде: длиннее, но читаемее и гибче.
Проверьте себя
1. Что проверяет фрагмент (?=.*\d) в начале паттерна пароля?
AЧто строка начинается с цифры
BЧто где-то в строке есть хотя бы одна цифра, не сдвигая позицию
CЧто строка состоит только из цифр
DЧто цифр ровно одна
2. Почему порядок символов в пароле не важен для паттерна с несколькими lookahead?
AПотому что lookahead сортирует символы
BПотому что все lookahead проверяются из одной точки (начала) и каждый независимо сканирует всю строку
CПотому что используется флаг IGNORECASE
DПорядок на самом деле важен
3. Что добавляет .{8,}$ в конце паттерна ^(?=...)(?=...).{8,}$?
AТребование, что в строке не меньше 8 символов до конца
BРовно 8 символов
CЛюбые 8 цифр
DНеобязательную часть
Поддержать проект