← Назад к курсу
Использованию регулярных выражений в Python
Введение
Регулярные выражения (regex) - мощный инструмент для поиска и обработки текста по шаблонам. В Python они реализованы в модуле re.
1. Основные методы модуля re
Импорт модуля
import re
Основные функции:
text = "Мой телефон: +7-999-123-45-67, email: test@example.com"
# re.search() - поиск первого совпадения
match = re.search(r'\d{2}', text) # ищет 2 цифры подряд
print(match.group()) if match else print("Не найдено")
# re.findall() - поиск всех совпадений
numbers = re.findall(r'\d+', text) # все последовательности цифр
print(numbers) # ['7', '999', '123', '45', '67']
# re.finditer() - итератор по совпадениям
for match in re.finditer(r'\d+', text):
print(f"Найдено: {match.group()} на позиции {match.start()}-{match.end()}")
# re.sub() - замена по шаблону
new_text = re.sub(r'\d', '#', text) # заменяем все цифры на #
print(new_text)
# re.split() - разделение по шаблону
parts = re.split(r'[:,]', text) # разделяем по : или ,
print(parts)
2. Основные элементы регулярных выражений
Специальные символы:
# . - любой символ, кроме новой строки print(re.findall(r't.st', 'test tast t3st')) # ['test', 'tast', 't3st'] # ^ - начало строки print(re.findall(r'^Мой', text)) # ['Мой'] # $ - конец строки print(re.findall(r'com$', 'test@example.com')) # ['com'] # \d - цифра, \D - не цифра print(re.findall(r'\d+', 'abc123xyz')) # ['123'] print(re.findall(r'\D+', 'abc123xyz')) # ['abc', 'xyz'] # \w - буква/цифра/_, \W - не \w print(re.findall(r'\w+', 'Hello_123! Test.')) # ['Hello_123', 'Test'] # \s - пробельный символ, \S - не \s print(re.findall(r'\S+', 'Hello World\nTest')) # ['Hello', 'World', 'Test'] # [] - набор символов print(re.findall(r'[aeiou]', 'Hello World')) # ['e', 'o', 'o'] # [^] - исключающий набор print(re.findall(r'[^aeiou\s]', 'Hello World')) # ['H', 'l', 'l', 'W', 'r', 'l', 'd']
Квантификаторы (указатели количества):
# * - 0 или более раз
print(re.findall(r'\d*', 'a12b3c')) # ['', '12', '', '3', '']
# + - 1 или более раз
print(re.findall(r'\d+', 'a12b3c')) # ['12', '3']
# ? - 0 или 1 раз
print(re.findall(r'\d?', 'a12b3c')) # ['', '1', '2', '', '3', '']
# {n} - ровно n раз
print(re.findall(r'\d{2}', 'a123b4567c')) # ['12', '45', '67']
# {n,} - n или более раз
print(re.findall(r'\d{2,}', 'a123b4567c')) # ['123', '4567']
# {n,m} - от n до m раз
print(re.findall(r'\d{2,3}', 'a123b4567c')) # ['123', '456']
Группировка:
# () - группировка и захват
text = "Иван: 30 лет, Мария: 25 лет"
matches = re.findall(r'(\w+): (\d+)', text)
print(matches) # [('Иван', '30'), ('Мария', '25')]
# (?:) - не захватывающая группа
matches = re.findall(r'(?:\w+): (\d+)', text)
print(matches) # ['30', '25']
# | - или
print(re.findall(r'Иван|Мария', text)) # ['Иван', 'Мария']
3. Практические примеры
Валидация email:
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
emails = ["test@example.com", "invalid.email", "user.name@domain.co.uk"]
for email in emails:
print(f"{email}: {validate_email(email)}")
Извлечение телефонов:
def extract_phones(text):
# Российские номера в разных форматах
pattern = r'(\+7|8)[\s\-]?\(?\d{3}\)?[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}'
return re.findall(pattern, text)
text = """
Контакты: +7(999)123-45-67, 8-912-345-67-89,
+7 999 123 45 67, 89123456789
"""
print(extract_phones(text))
Парсинг логов:
log = """
2024-01-15 10:30:45 INFO: User logged in
2024-01-15 10:31:10 ERROR: Database connection failed
2024-01-15 10:32:00 WARNING: High memory usage
"""
pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (\w+): (.+)'
matches = re.findall(pattern, log)
for timestamp, level, message in matches:
print(f"{timestamp} [{level}] {message}")
Поиск и замена с callback:
def multiply_numbers(match):
number = int(match.group())
return str(number * 2)
text = "Цены: 100, 200, 300 рублей"
result = re.sub(r'\d+', multiply_numbers, text)
print(result) # Цены: 200, 400, 600 рублей
4. Флаги регулярных выражений
text = "Строка\nс\nразными\nрегистрами\nSTRING"
# re.IGNORECASE (re.I) - игнорирование регистра
print(re.findall(r'строка', text, re.IGNORECASE)) # ['Строка', 'STRING']
# re.MULTILINE (re.M) - многострочный режим
print(re.findall(r'^с', text, re.MULTILINE | re.IGNORECASE)) # ['с']
# re.DOTALL (re.S) - точка включает символ новой строки
print(re.findall(r'Строка.*STRING', text, re.DOTALL | re.IGNORECASE))
# re.VERBOSE (re.X) - разрешает комментарии и пробелы в шаблоне
pattern = re.compile(r'''
\d{3} # три цифры
-? # необязательный дефис
\d{2} # две цифры
-? # необязательный дефис
\d{2} # две цифры
''', re.VERBOSE)
5. Оптимизация и советы
Компиляция выражений:
# Для многократного использования
pattern = re.compile(r'\d{3}-\d{2}-\d{2}')
texts = ["123-45-67", "abc", "987-65-43"]
for text in texts:
match = pattern.search(text)
if match:
print(f"Найден: {match.group()}")
Использование сырых строк (raw strings):
# Всегда используйте сырые строки для regex pattern = r'\d+' # правильно pattern = '\\d+' # сложнее читать и писать
Избегайте жадных квантификаторов:
text = "<div>Первый</div><div>Второй</div>" # Жадный режим (по умолчанию) print(re.findall(r'<div>.*</div>', text)) # ['<div>Первый</div><div>Второй</div>'] # Ленивый режим print(re.findall(r'<div>.*?</div>', text)) # ['<div>Первый</div>', '<div>Второй</div>']
6. Упражнения для закрепления
# Задание 1: Извлечь все даты в формате DD.MM.YYYY
def extract_dates(text):
pattern = r'\b\d{2}\.\d{2}\.\d{4}\b'
return re.findall(pattern, text)
# Задание 2: Проверить сложность пароля
def check_password(password):
"""
Пароль должен содержать:
- минимум 8 символов
- хотя бы одну цифру
- хотя бы одну букву в верхнем регистре
- хотя бы одну букву в нижнем регистре
- хотя бы один специальный символ
"""
if len(password) < 8:
return False
if not re.search(r'\d', password):
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[a-z]', password):
return False
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
return False
return True
# Задание 3: Очистить текст от HTML-тегов
def remove_html_tags(text):
pattern = r'<[^>]+>'
return re.sub(pattern, '', text)
# Тестирование
if __name__ == "__main__":
# Тест для задания 1
test_text = "Даты: 15.01.2024, 20.12.2023, не дата 123.456.789"
print("Даты:", extract_dates(test_text))
# Тест для задания 2
passwords = ["Simple1!", "Complex123$", "weak", "NoSpecial1"]
for pwd in passwords:
print(f"{pwd}: {check_password(pwd)}")
# Тест для задания 3
html = "<h1>Заголовок</h1><p>Текст <b>жирный</b> и <i>курсив</i></p>"
print("Без тегов:", remove_html_tags(html))
Заключение
Регулярные выражения - мощный инструмент, который требует практики. Начните с простых паттернов, используйте онлайн-тестеры (regex101.com), и постепенно переходите к более сложным выражениям.
Дополнительные ресурсы:
- Документация Python: https://docs.python.org/3/library/re.html
- Regex101: https://regex101.com/ - для тестирования выражений
- RegexOne: https://regexone.com/ - интерактивное обучение