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

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

@potapov_me

Платформа

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

Контент

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

Компания

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

Аккаунт

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

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

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

Lookahead и lookbehind

Опережение и ретроспектива, положительные и отрицательные_assertions

Lookahead и lookbehind

Lookahead и lookbehind — это утверждения (assertions), которые проверяют наличие шаблона вперёд или назад без захвата текста. Мощный инструмент для сложных условий поиска.

#Что такое assertions

Assertions проверяют условие в позиции текста, но не захватывают символы:

  • ^ — начало строки
  • $ — конец строки
  • \b — граница слова
  • (?=...) — положительный lookahead
  • (?!...) — отрицательный lookahead
  • (?<=...) — положительный lookbehind
  • (?<!...) — отрицательный lookbehind

#Lookahead (опережение)

Lookahead проверяет, что следует после текущей позиции.

#Положительный lookahead (?=...)

Проверяет, что впереди есть указанный шаблон:

import re # Найти число, за которым следует 'руб' re.search(r'\d+(?=руб)', 'Цена: 100руб') # '100' re.search(r'\d+(?=руб)', 'Цена: 100$') # None # Без lookahead захватит и 'руб' re.search(r'\d+руб', 'Цена: 100руб') # '100руб'

#Отрицательный lookahead (?!...)

Проверяет, что впереди НЕТ указанного шаблона:

# Найти число, за которым НЕ следует 'руб' re.search(r'\d+(?!руб)', 'Цена: 100$') # '100' re.search(r'\d+(?!руб)', 'Цена: 100руб') # None # Проверка сложного пароля (без последовательных одинаковых символов) re.search(r'^(?!.*(\w)\1).{8,}$', 'abc12345') # None — есть '11' re.search(r'^(?!.*(\w)\1).{8,}$', 'abcdefgh') # Match

#Lookbehind (ретроспектива)

Lookbehind проверяет, что было перед текущей позицией.

#Положительный lookbehind (?<=...)

Проверяет, что перед позицией есть указанный шаблон:

# Найти число, перед которым стоит '$' re.search(r'(?<=\$)\d+', 'Price: $100') # '100' re.search(r'(?<=\$)\d+', 'Price: 100$') # None # Без lookbehind захватит и '$' re.search(r'\$\d+', 'Price: $100') # '$100'

#Отрицательный lookbehind (?<!...)

Проверяет, что перед позицией НЕТ указанного шаблона:

# Найти число, перед которым НЕ стоит '$' re.search(r'(?<!\$)\d+', 'Price: 100') # '100' re.search(r'(?<!\$)\d+', 'Price: $100') # None # Найти слово без префикса 'un' re.search(r'(?<!un)\w+', 'happy') # 'happy' re.search(r'(?<!un)\w+', 'unhappy') # 'happy' — найдёт 'happy' после 'un'

#Комбинирование lookahead и lookbehind

Можно использовать оба утверждения одновременно:

# Найти число между '$' и 'руб' re.search(r'(?<=\$)\d+(?=руб)', '$100руб') # '100' # Извлечение значения из строки формата text = 'Цена: $150руб, Скидка: $50руб' re.findall(r'(?<=\$)\d+(?=руб)', text) # ['150', '50']

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

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

# Минимум 8 символов, хотя бы одна буква и одна цифра pattern = r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$' # (?=.*[A-Za-z]) — есть хотя бы одна буква # (?=.*\d) — есть хотя бы одна цифра # [A-Za-z\d]{8,} — только буквы и цифры, минимум 8 bool(re.match(pattern, 'password1')) # True bool(re.match(pattern, 'password')) # False — нет цифры bool(re.match(pattern, 'pass1')) # False — меньше 8

#2. Извлечение текста без кавычек

text = '"hello" and "world"' # Без lookbehind/lookahead re.findall(r'"([^"]*)"', text) # ['hello', 'world'] — с группой # С lookbehind и lookahead re.findall(r'(?<=")[^"]*(?=")', text) # ['hello', 'world'] — без группы

#3. Поиск слов в определённом контексте

text = 'The cat sat on the cat mat' # 'cat' не после 'the ' re.findall(r'(?<!the )cat', text, re.IGNORECASE) # ['cat'] — второй 'cat' # 'cat' не перед ' mat' re.findall(r'cat(?! mat)', text, re.IGNORECASE) # ['cat'] — первый 'cat'

#4. Валидация email с ограничениями

# Email не должен начинаться или заканчиваться на точку pattern = r'^(?!\.)[\w.-]+[\w-](?<!\.)@[\w.-]+\.[a-zA-Z]{2,}$' # (?!\.) — не начинается с точки # (?<!\.) — не заканчивается на точку перед @ bool(re.match(pattern, 'user@example.com')) # True bool(re.match(pattern, '.user@example.com')) # False bool(re.match(pattern, 'user.@example.com')) # False

#5. Извлечение значений после ключа

text = 'name: John, age: 30, city: Moscow' # Значение после 'age: ' re.search(r'(?<=age: )\d+', text) # '30' # Все значения после ': ' re.findall(r'(?<=: )[^,]+', text) # ['John', '30', 'Moscow']

#Ограничения lookbehind

В стандартном re lookbehind требует фиксированной длины:

# Работает: фиксированная длина re.search(r'(?<=\$)\d+', '$100') # '100' # Ошибка: переменная длина re.search(r'(?<=\${1,3})\d+', '$$$100') # error: look-behind requires fixed-width pattern # Решение: использовать альтернативу re.search(r'\${1,3}(\d+)', '$$$100') # '100' — с группой

Примечание: В Python 3.11+ и библиотеке regex это ограничение снято.

#Lookahead с альтернативой

# Найти число перед 'руб' или '$' re.findall(r'\d+(?=руб|\$)', 'Цена: 100руб или $200') # ['100', '200'] # Найти слово перед '!' или '?' re.findall(r'\w+(?=[!?])', 'Hello! How are you?') # ['Hello', 'you']

#Вложенные assertions

Можно комбинировать несколько assertions:

# Пароль: минимум 8 символов, буква, цифра, спецсимвол pattern = r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$' # (?=.*[A-Za-z]) — есть буква # (?=.*\d) — есть цифра # (?=.*[@$!%*?&]) — есть спецсимвол bool(re.match(pattern, 'Pass123!')) # True bool(re.match(pattern, 'Password')) # False — нет цифры и спецсимвола

#Отладка assertions

Assertions не захватывают текст, что может запутать:

# Lookahead не захватывает 'руб' match = re.search(r'\d+(?=руб)', '100руб') match.group() # '100' — только число # Для захвата используйте группу match = re.search(r'(\d+)руб', '100руб') match.group(1) # '100'

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

#1. Переменная длина в lookbehind

# Ошибка в re: переменная длина re.search(r'(?<=\${1,3})\d+', '$$$100') # error # Решение: фиксированная длина или альтернатива re.search(r'(?<=\$)\d+', '$$$100') # '$$100' — не то re.search(r'\${1,3}(\d+)', '$$$100') # '100' — правильно

#2. Lookahead в неправильном месте

# Ошибка: lookahead после цифр проверяет то, что после цифр re.search(r'\d+(?=руб)', 'руб100') # None # Правильно: lookahead должен быть после позиции проверки re.search(r'(?<=руб)\d+', 'руб100') # '100'

#3. Забытый якорь начала

# Ошибка: без ^ проверка в любом месте строки re.search(r'(?=.*\d).{8,}', 'abc12345extra') # Match — но может быть не то # Правильно: с ^ для проверки всей строки re.search(r'^(?=.*\d).{8,}$', 'abc12345') # Match

Далее: Флаги и модификаторы