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

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

@potapov_me

Платформа

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

Контент

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

Компания

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

Аккаунт

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

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

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

Группы и захват

Нумерованные и именованные группы, non-capturing группы, backreferences

Группы и захват

Группы позволяют выделять части совпадения для последующего извлечения или использования. Это мощный инструмент для структурирования данных.

#Синтаксис групп

Группы создаются с помощью круглых скобок ():

import re # Простая группа match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2024-03-09') match.groups() # ('2024', '03', '09') match.group(0) # '2024-03-09' — всё совпадение match.group(1) # '2024' — первая группа match.group(2) # '03' — вторая группа match.group(3) # '09' — третья группа

#Нумерованные группы

Группы нумеруются слева направо по открывающим скобкам:

# Вложенные группы match = re.search(r'((\w+)\s+(\w+))', 'Hello World') match.group(0) # 'Hello World' — всё совпадение match.group(1) # 'Hello World' — первая группа (внешняя) match.group(2) # 'Hello' — вторая группа match.group(3) # 'World' — третья группа

#Именованные группы

Именованные группы позволяют обращаться по имени вместо номера:

# Синтаксис: (?P<имя>паттерн) match = re.search(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', '2024-03-09') match.group('year') # '2024' match.group('month') # '03' match.group('day') # '09' match.groupdict() # {'year': '2024', 'month': '03', 'day': '09'}

#Преимущества именованных групп

# Более читаемый код pattern = r'(?P<email>\w+@\w+\.\w+):(?P<phone>\d+)' match = re.search(pattern, 'user@example.com:123456') email = match.group('email') # Понятно, что извлекаем phone = match.group('phone') # Не нужно помнить номера групп

#Non-capturing группы (?:...)

Группы ?: группируют элементы, но не захватывают совпадение:

# Обычная группа — захватывает re.search(r'(ab)+', 'abab') # group(1) = 'ab' # Non-capturing группа — не захватывает re.search(r'(?:ab)+', 'abab') # group(1) вызовет ошибку — группы нет # Практический пример: протокол URL re.search(r'(https?|ftp)://', 'https://example.com') # group(1) = 'https' re.search(r'(?:https?|ftp)://', 'https://example.com') # Нет группы, толькосоответствует

#Когда использовать non-capturing группы

  1. Применение квантификатора к группе:

    # Повторение группы протоколов re.search(r'(?:https?|ftp)://\w+', 'https://example.com')
  2. Альтернатива без захвата:

    # Mr, Mrs, Ms без захвата re.search(r'(?:Mr|Mrs|Ms)\. \w+', 'Mr. Smith')
  3. Улучшение производительности: Non-capturing группы немного быстрее, так как не сохраняют совпадение.

#Backreferences — ссылки на группы

Используйте захваченные группы в том же паттерне:

# Поиск повторяющихся слов re.search(r'\b(\w+)\s+\1\b', 'hello hello world') # 'hello hello' # \1 ссылается на первую группу

#Именованные backreferences

# Синтаксис: (?P=name) re.search(r'\b(?P<word>\w+)\s+(?P=word)\b', 'hello hello') # 'hello hello'

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

# Поиск одинарных кавычек re.search(r'"[^"]*"', '"hello"') # '"hello"' # Поиск парных тегов HTML re.search(r'<(\w+)>(.*?)</\1>', '<div>content</div>') # '<div>content</div>' # \1 ссылается на название тега из первой группы # Удвоение символов re.search(r'(\w)\1', 'book') # 'oo' re.search(r'(\w)\1', 'look') # 'oo'

#Извлечение данных с группами

#findall с группами

# Без групп — список полных совпадений re.findall(r'\d+-\d+', '1-2 3-4') # ['1-2', '3-4'] # С группами — список кортежей групп re.findall(r'(\d+)-(\d+)', '1-2 3-4') # [('1', '2'), ('3', '4')] # С именованными группами — тоже кортежи re.findall(r'(?P<a>\d+)-(?P<b>\d+)', '1-2 3-4') # [('1', '2'), ('3', '4')]

#finditer для итерации

text = '2024-03-09, 2023-01-15, 2022-12-31' for match in re.finditer(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', text): print(f"{match.group('day')}.{match.group('month')}.{match.group('year')}") # 09.03.2024 # 15.01.2023 # 31.12.2022

#Замена с использованием групп

#sub с backreferences

# Замена формата даты text = '2024-03-09' re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3.\2.\1', text) # '09.03.2024' # С именованными группами re.sub(r'(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})', r'\g<d>.\g<m>.\g<y>', text)

#sub с функцией

def replace_date(match): year, month, day = match.groups() return f'{day}.{month}.{year}' re.sub(r'(\d{4})-(\d{2})-(\d{2})', replace_date, '2024-03-09') # '09.03.2024'

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

#1. Парсинг имени и фамилии

text = 'Иванов Иван' match = re.search(r'(?P<lastname>\w+)\s+(?P<firstname>\w+)', text) lastname = match.group('lastname') # 'Иванов' firstname = match.group('firstname') # 'Иван'

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

html = '<a href="https://example.com">Example</a>' match = re.search(r'<a\s+href="(?P<url>[^"]+)">(?P<text>[^<]+)</a>', html) url = match.group('url') # 'https://example.com' text = match.group('text') # 'Example'

#3. Валидация повторяющихся символов

# Запретить повторяющиеся символы в пароле def has_no_repeats(password): return not re.search(r'(\w)\1', password) has_no_repeats('abc123') # True has_no_repeats('aabc123') # False — 'aa'

#4. Нормализация телефона

phone = '+7 (999) 123-45-67' # Извлечение цифр digits = re.sub(r'\D', '', phone) # '79991234567' # Форматирование match = re.search(r'(\d)(\d{3})(\d{3})(\d{2})(\d{2})', digits) if match: formatted = '+{} ({}) {}-{}-{}'.format(*match.groups()) # '+7 (999) 123-45-67'

#Вложенные группы

# Вложенные группы нумеруются по порядку открывающих скобок pattern = r'((\w+)\s+(\w+))' match = re.search(pattern, 'Hello World') match.group(0) # 'Hello World' — всё совпадение match.group(1) # 'Hello World' — первая группа (внешняя) match.group(2) # 'Hello' — вторая группа match.group(3) # 'World' — третья группа

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

#1. Неправильный номер группы

match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '2024-03-09') match.group(0) # '2024-03-09' — всё совпадение match.group(1) # '2024' — первая группа match.group(4) # IndexError — всего 3 группы

#2. Забытая группа в findall

# Хотим получить все числа re.findall(r'\d+-\d+', '1-2 3-4') # ['1-2', '3-4'] — правильно # Но с группами получаем кортежи re.findall(r'(\d+)-(\d+)', '1-2 3-4') # [('1', '2'), ('3', '4')] # Решение: non-capturing группа или обработка кортежей re.findall(r'(?:\d+)-(\d+)', '1-2 3-4') # ['2', '4'] — только вторая цифра

#3. Backreference вне паттерна

# \1 работает только внутри patтерна re.sub(r'(\d+)', r'\1', '123') # '123' — правильно # Но в findall \1 не работает re.findall(r'(\d+)\1', '123123') # ['123'] — ищет повторяющиеся цифры

Далее: Методы re модуля