Python - Регулярные выражения

Приветствуем, будущие маги Python! Сегодня мы отправляемся в захватывающее путешествие в мир регулярных выражений (regex) в Python. Не волнуйтесь, если вы никогда не слышали о regex раньше - к концу этого урока вы сможете мастерски использовать этот мощный инструмент!

Python - Reg Expressions

Что такое регулярные выражения?

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

Сырые строки

В Python, работая с regex, мы часто используем сырые строки. Они начинаются с символа 'r' и обрабатывают символы обратной косой черты как литеральные символы. Это особенно полезно в regex, так как обратные косые черты встречаются часто.

# Обычная строка
print("Hello\nWorld")
# Сырая строка
print(r"Hello\nWorld")

В первом случае вы увидите "Hello" и "World" на разных строках. Во втором случае вы увидите "Hello\nWorld" как есть. Это становится критически важным при работе с шаблонами regex.

Метасимволы

Метасимволы - это строительные блоки regex. У них есть особое значение, и они помогают нам определять шаблоны. Давайте рассмотрим некоторые из них:

Метасимвол Значение
. Совпадает с любым символом, кроме новой строки
^ Совпадает с началом строки
$ Совпадает с концом строки
* Совпадает 0 или более повторений
+ Совпадает 1 или более повторений
? Совпадает 0 или 1 повторение
{} Совпадает с явно указанным количеством повторений
[] Указывает набор символов для совпадения
\ Экранирует специальные символы

Функция re.match()

Функция re.match() пытается найти совпадение шаблона в начале строки. Если она находит совпадение, она возвращает объект совпадения; в противном случае возвращает None.

import re

result = re.match(r"Hello", "Hello, World!")
if result:
print("Совпадение найдено:", result.group())
else:
print("Нет совпадения")

Это выведет "Совпадение найдено: Hello". Метод group() возвращает совпадающую подстроку.

Функция re.search()

В то время как re.match() ищет совпадение в начале строки, re.search() сканирует всю строку для поиска совпадения.

import re

result = re.search(r"World", "Hello, World!")
if result:
print("Совпадение найдено:", result.group())
else:
print("Нет совпадения")

Это выведет "Совпадение найдено: World".

Сравнение match() и search()

Основное различие между match() и search() заключается в том, что match() проверяет совпадение только в начале строки, в то время как search() проверяет совпадение где угодно в строке.

Функция re.findall()

Функция re.findall() возвращает все не перекрывающиеся совпадения шаблона в строке в виде списка.

import re

text = "The rain in Spain falls mainly in the plain"
result = re.findall(r"ain", text)
print(result)

Это выведет ['ain', 'ain', 'ain'].

Функция re.sub()

Функция re.sub() заменяет все вхождения шаблона в строке на строку замены.

import re

text = "The rain in Spain"
result = re.sub(r"a", "o", text)
print(result)

Это выведет "The roin in Spoin".

Функция re.compile()

Функция re.compile() создает объект regex для повторного использования, что может быть более эффективным, если вы используете один и тот же шаблон многократно.

import re

pattern = re.compile(r"\d+")
result1 = pattern.findall("There are 123 apples and 456 oranges")
result2 = pattern.findall("I have 789 bananas")

print(result1)
print(result2)

Это выведет ['123', '456'] и ['789'].

Функция re.finditer()

Функция re.finditer() возвращает итератор, выдающий объекты совпадения для всех не перекрывающихся совпадений шаблона в строке.

import re

text = "The rain in Spain"
for match in re.finditer(r"ain", text):
print(f"Найдено '{match.group()}' в позиции {match.start()}-{match.end()}")

Это выведет:

Найдено 'ain' в позиции 5-8
Найдено 'ain' в позиции 17-20

Примеры использования Python Regex

Регулярные выражения имеют множество практических применений. Рассмотрим общий случай использования:

Найти слова, начинающиеся с гласных

import re

text = "An apple a day keeps the doctor away"
vowel_words = re.findall(r'\b[aeiouAEIOU]\w+', text)
print(vowel_words)

Это выведет ['An', 'apple', 'a', 'away'].

Модификаторы регулярных выражений: флаги опций

Модуль re Python предоставляет несколько флагов опций, которые изменяют интерпретацию шаблонов:

Флаг Описание
re.IGNORECASE (re.I) выполняет нечувствительное к регистру сравнение
re.MULTILINE (re.M) делает ^ совпадающим с началом каждой строки и $ концом каждой строки
re.DOTALL (re.S) делает . совпадающим с любым символом, включая новую строку
re.VERBOSE (re.X) позволяет писать более читаемые шаблоны regex

Регулярные выражения шаблонов

Рассмотрим некоторые более сложные шаблоны:

Классы символов

Классы символов позволяют указывать набор символов для совпадения:

import re

text = "The quick brown fox jumps over the lazy dog"
result = re.findall(r"[aeiou]", text)
print(result)

Это выведет все гласные буквы, найденные в тексте.

Специальные классы символов

Python regex поддерживает специальные классы символов:

Класс Описание
\d совпадает с любым десятичным числом
\D совпадает с любым нецифровым символом
\s совпадает с любым пробельным символом
\S совпадает с любым не пробельным символом
\w совпадает с любым буквенно-цифровым символом
\W совпадает с любым не буквенно-цифровым символом

Повторения

Мы можем указать, сколько раз должен встречаться шаблон:

import re

text = "I have 111 apples and 22 oranges"
result = re.findall(r"\d{2,3}", text)
print(result)

Это выведет ['111', '22'], совпадая с числами с 2 или 3 цифрами.

Ненасыщенные повторения

По умолчанию повторение является насыщенным, то есть совпадает с максимально возможным количеством повторений. Добавление ? после повторения делает его ненасыщенным:

import re

text = "<h1>Title</h1><p>Paragraph</p>"
greedy = re.findall(r"<.*>", text)
non_greedy = re.findall(r"<.*?>", text)
print("Насыщенное:", greedy)
print("Ненасыщенное:", non_greedy)

Это покажет разницу между насыщенным и ненасыщенным совпадением.

Группировка с помощью скобок

Скобки позволяют группировать части regex:

import re

text = "John Smith ([email protected])"
result = re.search(r"(\w+) (\w+) \((\w+@\w+\.\w+)\)", text)
if result:
print(f"Полное имя: {result.group(1)} {result.group(2)}")
print(f"Электронная почта: {result.group(3)}")

Это извлекает имя и адрес электронной почты из текста.

Обратные ссылки

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

import re

text = "<h1>Title</h1><p>Paragraph</p>"
result = re.findall(r"<(\w+)>.*?</\1>", text)
print(result)

Это совпадает с открывающими и закрывающими тегами HTML.

Альтернативы

Символ | позволяет указывать альтернативы:

import re

text = "The color of the sky is blue or gray"
result = re.search(r"blue|gray", text)
if result:
print(f"Найден цвет: {result.group()}")

Это совпадает либо с "blue", либо с "gray".

Привязки

Привязки указывают позиции в тексте:

import re

text = "Python is awesome"
start = re.match(r"^Python", text)
end = re.search(r"awesome$", text)
print(f"Начинается с Python: {bool(start)}")
print(f"Заканчивается на awesome: {bool(end)}")

Это проверяет, начинается ли текст с "Python" и заканчивается ли на "awesome".

Специальная синтаксис с помощью скобок

Скобки могут использоваться не только для группировки:

  • (?:...) создает некаптурирующую группу
  • (?P...) создает именованную группу
  • (?=...) создает положительное предварительное совпадение
  • (?!...) создает отрицательное предварительное совпадение
import re

text = "Python version 3.9.5"
result = re.search(r"Python (?:version )?(?P<version>\d+\.\d+\.\d+)", text)
if result:
print(f"Версия: {result.group('version')}")

Это извлекает номер версии, будь то "version" присутствует в тексте или нет.

Итак, это было наше путешествие по миру Python regex, от основ к более сложным концепциям. Помните, как и любое мощное инструмент, regex требует практики для мастерства. Так что не расстраивайтесь, если в начале это кажется сложным. Продолжайте экспериментировать, и скоро вы сможете искать шаблоны как настоящий сыщик! Удачи в кодинге!

Credits: Image by storyset