Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Квантификаторы
quantifiers

Квантификаторы

Количество повторений, greedy vs non-greedy, владение

Квантификаторы

Квантификаторы указывают, сколько раз должен повторяться предыдущий элемент шаблона. Это ключевой инструмент для гибкого поиска.

#Основные квантификаторы

КвантификаторЗначениеПример
*0 или болееa* — '', 'a', 'aa', ...
+1 или болееa+ — 'a', 'aa', ...
?0 или 1a? — '', 'a'
{n}ровно na{3} — 'aaa'
{n,}n или болееa{2,} — 'aa', 'aaa', ...
{n,m}от n до ma{2,4} — 'aa', 'aaa', 'aaaa'

#Звёздочка (*) — ноль или более

import re # Ноль или более букв 'a' re.search(r'a*', 'bbb') # '' (пустая строка в начале) re.search(r'a*', 'abb') # 'a' re.search(r'a*', 'aaabb') # 'aaa' # Практический пример: пробельные символы re.search(r'\s*', 'hello') # '' (нет пробелов) re.search(r'\s*', ' hello') # ' ' (два пробела)

Важно: * может соответствовать пустой строке, что иногда приводит к неожиданным результатам.

#Плюс (+) — один или более

# Один или более букв 'a' re.search(r'a+', 'bbb') # None (нет 'a') re.search(r'a+', 'abb') # 'a' re.search(r'a+', 'aaabb') # 'aaa' # Практический пример: числа re.search(r'\d+', 'abc123def') # '123' re.findall(r'\d+', 'a1b23c456') # ['1', '23', '456']

#Вопросительный знак (?) — ноль или один

# Ноль или один символ 's' (множественное число) re.search(r'cats?', 'cat') # 'cat' re.search(r'cats?', 'cats') # 'cats' # Опциональный дефис в телефоне re.search(r'\d{3}-?\d{4}', '1234567') # '1234567' re.search(r'\d{3}-?\d{4}', '123-4567') # '123-4567'

#Фигурные скобки ({n,m}) — точное количество

# Ровно 3 цифры re.search(r'\d{3}', 'abc123def') # '123' # От 2 до 4 букв re.search(r'[a-z]{2,4}', 'abcdef') # 'abcd' (жадно) # 3 или более цифр re.search(r'\d{3,}', '12345') # '12345'

#Практические примеры

# Дата в формате YYYY-MM-DD re.search(r'\d{4}-\d{2}-\d{2}', '2024-03-09') # '2024-03-09' # Время в формате HH:MM re.search(r'\d{2}:\d{2}', '14:30') # '14:30' # HEX-цвет re.search(r'#[0-9a-fA-F]{6}', '#FF5733') # '#FF5733'

#Жадные (greedy) vs нежадные (non-greedy) квантификаторы

По умолчанию квантификаторы жадные — захватывают максимально возможное количество символов.

#Жадный режим (по умолчанию)

text = '<div>content</div>' # Жадный: захватит всё от первого < до последнего > re.search(r'<.*>', text) # '<div>content</div>'

#Нежадный режим (ленивый)

Добавьте ? после квантификатора для минимального захвата:

# Нежадный: захватит минимальное количество re.search(r'<.*?>', text) # '<div>' # Все теги по отдельности re.findall(r'<.*?>', text) # ['<div>', '</div>']

#Сравнение жадного и нежадного режима

text = '"first" and "second"' # Жадный: захватит всё между первой и последней кавычкой re.search(r'".*"', text) # '"first" and "second"' # Нежадный: захватит каждую цитату отдельно re.findall(r'.*?"', text) # ['"', '"'] # кавычки re.findall(r'"[^"]*"', text) # ['"first"', '"second"'] # правильно!

#Владеющие квантификаторы (possessive)

В стандартном re нет possessive квантификаторов, но они есть в библиотеке regex:

# В библиотеке regex: import regex # Possessive: захватывает и не отдаёт при backtracking regex.search(r'a++b', 'aaaaac') # None — быстрее, чем a+b

#Как работают квантификаторы с backtracking

При неудачном совпадении движок возвращается назад (backtracking):

# Шаблон ищет 'a' один или более, затем 'b' re.search(r'a+b', 'aaaaac') # None # Процесс: # 1. a+ захватывает 'aaaaa' # 2. b несоответствует 'c' # 3. Backtracking: a+ отдаёт одну 'a' # 4. b несоответствует 'a' # 5. Продолжается пока a+ не отдаст все 'a' # 6. b несоответствует 'a', результат None

#Практические примеры

#1. Валидация пароля

# Минимум 8 символов pattern = r'^.{8,}$' bool(re.match(pattern, 'password')) # False — 8 символов, ок bool(re.match(pattern, 'pass')) # False — меньше 8

#2. Извлечение текста между тегами

html = '<p>First</p><p>Second</p>' # Жадный — неправильно re.findall(r'<p>.*</p>', html) # ['<p>First</p><p>Second</p>'] # Нежадный — правильно re.findall(r'<p>.*?</p>', html) # ['<p>First</p>', '<p>Second</p>']

#3. Поиск email

text = 'Email: user@example.com, admin@test.org' # Простой паттерн re.findall(r'\w+@\w+\.\w+', text) # ['user@example.com', 'admin@test.org']

#4. Нормализация пробелов

text = 'Hello world with extra spaces' # Заменить множественные пробелы на один re.sub(r'\s+', ' ', text) # 'Hello world with extra spaces'

#Распространённые ошибки

#1. Catastrophic backtracking

# Опасный паттерн: (a+)+ на длинной строке без 'b' pattern = r'(a+)+b' text = 'a' * 30 + 'c' # re.search(pattern, text) # Будет выполняться очень долго! # Решение: используйте possessive или atomic groups (в regex) # Или упростите паттерн: a+b

#2. Жадный захват слишком много

text = '<div>content</div>' # Ошибка: жадный захват re.search(r'<.*>', text) # '<div>content</div>' # Правильно: нежадный re.search(r'<.*?>', text) # '<div>'

#3. Пустое совпадение со звёздочкой

# * можетсоответствует пустую строку re.findall(r'a*', 'bbb') # ['', '', '', ''] — 4 пустых совпадения! # Используйте + для хотя бы одного символа re.findall(r'a+', 'bbb') # [] — правильно

Далее: Группы и захват