Регулярные выражения (Regular Expressions или сокращенно regex) представляют собой мощный инструмент для поиска, анализа и манипулирования текстовой информацией с использованием шаблонов.
В чем преимущества регулярных выражений?
Рассмотрим примеры поиска email и телефонного номера в большом текстовом файле.
- Первый пример ищет email с использованием строгого регулярного выражения, проверяющего формат адреса.
- Второй пример ищет email без использования регулярных выражений, что делает код менее читаемым и гибким.
- Третий пример находит номер телефона с использованием регулярных выражений и затем удаляет все символы, кроме цифр.
- Четвертый пример ищет номер телефона без использования регулярных выражений, что также делает код менее компактным и подверженным ошибкам.
Пример 1: Поиск email с использованием регулярных выражений:
import re
def find_emails_with_regex(text):
pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
result = re.findall(pattern, text)
return result
Пример 2: Поиск email без использования регулярных выражений:
def find_emails_in_array(text_array):
result = []
for text in text_array:
words = text.split()
for word in words:
if '@' in word and '.' in word:
# Дополнительная проверка на недопустимые символы
if all(char.isalpha() or char.isdigit() or char in ['.', '_', '-', '%', '+'] for char in word):
result.append(word)
return result
Пример 3: Поиск номеров телефонов с использованием регулярных выражений:
import re
def find_phone_numbers_with_regex(text):
pattern = r'[\d()+\- ]+'
# Находим номер телефона с использованием регулярного выражения
matched_text = re.search(pattern, text).group()
# Очищаем номер телефона от лишних символов
result = re.sub(r'\D', '', matched_text)
return result
Пример 4: Поиск номеров телефонов в массиве текста с очисткой от лишних символов:
def find_phone_numbers_in_array(text_array):
result = []
for text in text_array:
chars_to_remove = '()-+ '
current_phone = ''
for char in text:
if char.isdigit() or char in chars_to_remove:
current_phone += char
# Добавляем только непустые номера телефонов
if current_phone:
result.append(current_phone)
return result
Недостатки примеров без использования регулярных выражений:
- Ограниченная точность: Простые методы, такие как разделение строки на слова и поиск определенных символов, не гарантируют точное соответствие формату, и могут ошибочно находить или пропускать нужные элементы. Например, при поиске email адресов, подход с простым поиском символа «@» и «.» может привести к неверным результатам.
- Низкая гибкость: Методы без использования регулярных выражений могут быть менее гибкими в адаптации к различным форматам данных. Если формат данных изменится, код также потребует изменений.
- Больше кода: Для решения сложных задач без регулярных выражений может потребоваться написание большего объема кода, что сделает его менее читаемым и увеличит вероятность ошибок.
- Неудобство в обслуживании: Обслуживание и расширение кода может стать сложнее без использования регулярных выражений, особенно при необходимости внесения изменений в условия поиска.
- Отсутствие поддержки специфичных форматов: Некоторые задачи, такие как поиск email адресов или номеров телефонов, имеют четкие форматы, которые легко описываются регулярными выражениями, но которые сложно обработать с использованием простых методов.
Преимущества регулярных выражений:
- Гибкость и мощь: Регулярные выражения позволяют создавать сложные шаблоны, охватывающие различные случаи и форматы текста. Это делает их эффективным средством для поиска и извлечения информации из текстовых данных.
- Универсальность: Регулярные выражения поддерживаются во многих языках программирования и текстовых редакторах, что делает их универсальным инструментом для обработки текста в различных сценариях.
- Эффективность: При правильном использовании регулярные выражения могут быть очень эффективными, особенно при работе с большими объемами текстовых данных.
- Компактность: С помощью регулярных выражений можно описать сложные условия поиска и замены с использованием относительно короткого шаблона, что делает код более читаемым и компактным.
- Автоматизация: Регулярные выражения позволяют автоматизировать процессы обработки текста, что особенно важно при анализе и преобразовании больших объемов данных.
Синтаксис регулярных выражений.
Основные символы, используемые в регулярных выражениях.
. (точка)- Назначение: Соответствует любому символу, кроме символа новой строки (
\n). - Пример:
a.cсоответствует строкам «abc», «adc», «a1c», и т. д.
- Назначение: Соответствует любому символу, кроме символа новой строки (
* (звездочка)- Назначение: Соответствует нулю или более повторениям предыдущего символа или группы символов.
- Пример:
ab*cсоответствует «ac», «abc», «abbc», «abbbc», и так далее.
+ (плюс)- Назначение: Соответствует одному или более повторениям предыдущего символа или группы символов.
- Пример:
ab+cсоответствует «abc», «abbc», «abbbc», и так далее.
? (вопросительный знак)- Назначение: Соответствует нулю или одному повторению предыдущего символа или группы символов.
- Пример:
ab?cсоответствует «ac» и «abc».
^ (caret)- Назначение: Соответствует началу строки.
- Пример:
^abcсоответствует строкам, начинающимся с «abc».
$ (доллар)- Назначение: Соответствует концу строки.
- Пример:
abc$соответствует строкам, заканчивающимся на «abc».
[ ] (квадратные скобки)- Назначение: Соответствует одному из символов, перечисленных в скобках.
- Пример:
[aeiou]соответствует любой гласной букве.
[^ ] (квадратные скобки с отрицанием)- Назначение: Соответствует любому символу, не входящему в список в скобках.
- Пример:
[^0-9]соответствует любому символу, не являющемуся цифрой.
| (вертикальная черта)- Назначение: Или (или «или это, или то»).
- Пример:
cat|dogсоответствует «cat» или «dog».
( ) (круглые скобки)- Назначение: Группировка выражения.
- Пример:
(ab)+соответствует «ab», «abab», «ababab», и так далее.
\ (обратная косая черта)- Назначение: Экранирование специальных символов. Например,
\.,\\и так далее.
- Назначение: Экранирование специальных символов. Например,
\d, \D, \w, \W, \s, \S- Назначение: Специальные последовательности для соответствия цифрам (
\d), не цифрам (\D), буквам и цифрам (\w), не буквам и не цифрам (\W), пробелам (\s), и не пробелам (\S).
- Назначение: Специальные последовательности для соответствия цифрам (
{ } (фигурные скобки)
- Назначение: Указание конкретного количества повторений предыдущего символа или группы символов.
- Примеры:
\d{2,4}— соответствует двум, трём или четырём цифрам.[a-zA-Z]{3}— соответствует трем буквам (регистр не имеет значения).
\b, \B
- Назначение: Границы слова (
\b) и отсутствие границы слова (\B). - Пример:
\bword\b— соответствует слову «word» как отдельному слову, но не включает «words» или «password».\Bword\B— соответствует «word» только если оно является частью другого слова.
(?i), (?s)
- Назначение: Установка флагов для регистронезависимого поиска (
(?i)) и режима «точка также совпадает с символом новой строки» ((?s)). - Пример:
(?i)case-insensitive— соответствует «case-insensitive», «CASE-INSENSITIVE», и так далее.
(?= ), (?! )
- Назначение: Позитивное впереди смотрящее утверждение (
(?= )) и негативное впереди смотрящее утверждение ((?! )). - Примеры:
\d(?=px)— соответствует цифре, если за ней следует «px».\d(?!px)— соответствует цифре, только если за ней НЕ следует «px».
(?: )
- Назначение: Негруппирующие скобки, которые позволяют группировать выражение без сохранения результатов.
- Пример:
(?:ab)+— соответствует «ab», «abab», «ababab», и так далее, но не создает захватывающих групп.
\1, \2, ...
- Назначение: Обратные ссылки на захватывающие группы.
\1ссылается на первую группу,\2— на вторую, и так далее. - Пример:
(\d{2})-\1— соответствует парам чисел, разделенных дефисом, где обе части одинаковы (например, «12-12», «34-34»).
*?, +?, ??
- Назначение: Ленивые (нежадные) версии квантификаторов
*,+, и?, которые соответствуют как можно меньшему количеству символов. - Пример:
a+?b— соответствует самому короткому возможному сочетанию символов «a» и «b» в строке.
\A, \Z
- Назначение: Соответствует началу строки (
\A) и концу строки (\Z), игнорируя символ новой строки. - Пример:
\Astart— соответствует строкам, начинающимся с «start».end\Z— соответствует строкам, заканчивающимся на «end».
Основные понятия, используемые в регулярных выражениях
- Метакаретка (^, $):
- Метакаретка — это специальный символ, который помогает нам указать, где должно начинаться (
^) или заканчиваться ($) соответствие в строке. - Пример:
^Helloсоответствует строкам, начинающимся с «Hello».
- Метакаретка — это специальный символ, который помогает нам указать, где должно начинаться (
- Набор символов ([ ]):
- Набор символов — это группа символов, из которых должен быть выбран один.
- Пример:
[aeiou]соответствует любой гласной букве.
- Квантификация (*, +, ?):
- Эти символы позволяют нам указать, сколько раз предыдущий символ или группа символов могут повторяться.
*— 0 или более раз.+— 1 или более раз.?— 0 или 1 раз.- Пример:
ab*cсоответствует «ac», «abc», «abbc», «abbbc», и так далее.
Пример квантификации с использованием фигурных скобок:
- Регулярное выражение
^[\d]{2,4}$говорит: «Начни со строки, затем должны быть от 2 до 4 цифр, и закончи строку». Это соответствует строкам вроде «123», «4567», «8901», но не соответствует строкам «12a» или «12345».
Группировка в RegExp
Группировка в регулярных выражениях нужна, чтобы сказать программе, какие части текста мы хотим рассматривать как единый блок или получить доступ к отдельным частям текста.
Группы в регулярных выражениях представляют собой механизм группировки и захвата подвыражений. Они создаются с использованием круглых скобок () вокруг части регулярного выражения. Группы могут использоваться для различных целей:
- Группировка выражений:
- Цель: Объединение частей регулярного выражения для обработки как единого блока.
- Пример:
(ab)+— создает группу для подвыражения «ab», а затем+указывает, что это подвыражение может повторяться один или более раз.
- Захват результатов:
- Цель: Захват значений, соответствующих определенным частям регулярного выражения.
- Пример:
(\d{2})-(\d{2})-(\d{4})— создает три группы для захвата дня, месяца и года в дате в формате «DD-MM-YYYY».
- Обратные ссылки:
- Цель: Использование значений, захваченных в группе, внутри того же регулярного выражения.
- Пример:
(\w+) \1— соответствует строкам, где одно и то же слово повторяется дважды, например, «apple apple» или «cat cat».
- Логические операции:
- Цель: Группы позволяют создавать сложные логические выражения.
- Пример:
(cat|dog)— создает группу, в которой указано «или» между «cat» и «dog», что соответствует строкам содержащим «cat» или «dog».
- Негруппирующие скобки
(?: ):- Цель: Создание группы без захвата результатов.
- Пример:
(?:ab)+— группирует «ab», но не сохраняет результат в захватываемой группе.
Обратные ссылки в регулярных выражениях
Обратные ссылки в регулярных выражениях позволяют ссылаться на текст, совпадающий с ранее захваченной группой внутри того же регулярного выражения. Это особенно полезно при создании шаблонов для поиска или замены текста.
Обратные ссылки обычно выражаются с использованием символов \ и номера группы. Как они работают:
\1: Ссылка на текст, совпадающий с первой захваченной группой.\2: Ссылка на текст, совпадающий со второй захваченной группой.- И так далее…
Примеры использования обратных ссылок.
Пример 1: Поиск повторяющихся слов:
import re
pattern = r'\b(\w+)\b\s+\1\b'
text = 'This is a test test.'
match = re.search(pattern, text)
if match:
print(f'Found repeated word: {match.group()}')
else:
print('No repeated word found')
#Found repeated word: test test
В этом примере шаблон \b(\w+)\b\s+\1\b ищет повторяющиеся слова. Обратная ссылка \1 ссылается на текст, совпадающий с первой захваченной группой, в данном случае, это слово «test».
Пример 2: Замена повторяющихся слов:
import re
pattern = r'\b(\w+)\b\s+\1\b'
text = 'This is a test test.'
new_text = re.sub(pattern, r'\1', text)
print(f'Original: {text}')
print(f'Replaced: {new_text}')
#Original: This is a test test.
#Replaced: This is a test.
В этом примере с использованием re.sub повторяющиеся слова удаляются из текста.
Примеры работы с группами и опережающими проверками
Захватывающие группы: что это и зачем
Что такое “группа”
Круглые скобки (...) — это группа. Она делает две вещи:
- Объединяет часть шаблона (как “кусочек” внутри большого выражения).
- Запоминает найденный текст, чтобы:
- потом к нему обратиться (
\1,\2и т. д.), - или получить его отдельно (в результатах поиска/замены).
Пример:
Шаблон: (кот)
Он найдёт слово “кот” и “запомнит” его как группу 1.
Как нумеруются группы
Группы нумеруются слева направо по открывающим скобкам:
(A)(B)(C)→ группа 1 = A, группа 2 = B, группа 3 = C((ab)c)→ группа 1 =(ab)c, группа 2 =ab
Как использовать захваченные группы
Повтор того же самого фрагмента (ссылки на группы)
(\w+)\s+\1 — “одно и то же слово два раза подряд”.
(\w+)— запомнили слово\s+— пробелы\1— повторяем то же, что было в группе 1
Строка: hello hello → совпадение есть
Строка: hello world → совпадения нет
Извлечь куски “по частям”
Например, хотим отдельно получить “день”, “месяц”, “год”:
Шаблон: (\d{2})\.(\d{2})\.(\d{4})
Строка: 31.12.2026
- группа 1:
31 - группа 2:
12 - группа 3:
2026
Замена с использованием групп
Меняем порядок “Фамилия Имя” → “Имя Фамилия”:
Найти: (\w+)\s+(\w+)
Заменить на: \2 \1
Строка: Иванов Пётр → станет Пётр Иванов
Небольшое уточнение: незахватывающие группы (?:...)
Иногда скобки нужны только чтобы “сгруппировать”, но ничего не запоминать. Тогда используют (?:...).
Пример:
(кот|пёс) — запомнит, что именно встретилось (кот или пёс)
(?:кот|пёс) — просто проверит вариант, но не создаст группу
Для начинающего правила простые:
- нужно потом использовать кусок →
(...) - не нужно использовать →
(?:...)(чтобы не путаться в номерах групп)
Опережающие проверки (lookahead): “проверить, но не забрать”
Опережающая проверка — это когда мы смотрим вперёд, убеждаемся, что там что-то есть/нет, но не включаем это в совпадение.
Позитивная опережающая проверка (?=...)
“Дальше должно быть …”
Пример: найти cat, но только если дальше идёт !
Шаблон: cat(?=!)
cat!→ найдётcat(восклицательный знак НЕ попадёт в совпадение)cat?→ не найдёт
Негативная опережающая проверка (?!...)
“Дальше НЕ должно быть …”
Пример: найти cat, но только если дальше НЕ идёт !
Шаблон: cat(?!!)
cat?→ найдётcatcat!→ не найдёт
Когда группы НЕ нужны?
Ситуация 1: просто проверить, есть ли подходящий фрагмент
Если вам не нужно:
- повторно использовать кусок,
- отдельно получать части совпадения,
- менять порядок при замене,
то группы не обязательны.
Задача: проверить, есть ли в тексте число из 3 цифр
Достаточно:
\d{3}
Группы тут ничего не дают, потому что:
- мы не вытаскиваем эти цифры отдельно
- не ссылаемся на них позже
Ситуация 2: выбор “или это, или то”
Задача: найти слово кот или пёс
Можно так:
кот|пёс
Группы не нужны, если:
- не используем результат отдельно
- не повторяем его позже
Ситуация 3: просто ограничить повторение
Задача: найти дату формата dd.mm.yyyy
Можно и так:
\d{2}\.\d{2}\.\d{4}
Если нам не важно отдельно получить день/месяц/год — группы не нужны.
Когда группы ТОЧНО нужны
Ситуация 1: нужно повторить ровно то же самое
Задача: найти два одинаковых слова подряд
❌ Без групп невозможно
✅ С группами легко:
(\w+)\s+\1
Почему без групп нельзя:
- нельзя сказать “повтори то же самое”, если мы это “то же самое” не запомнили
Ситуация 2: нужно извлечь части отдельно
Задача: из строки 31.12.2026 получить день, месяц и год
❌ Без групп — всё слипнется
✅ С группами:
(\d{2})\.(\d{2})\.(\d{4})
Ситуация 3: перестановка при замене
Задача: Иванов Пётр → Пётр Иванов
❌ Без групп невозможно
✅ С группами:
Поиск:
(\w+)\s+(\w+)
Замена:
\2 \1
Короткое правило про группы
Если вам нужно “помнить” кусок строки — без групп нельзя.
Если просто “проверить наличие” — группы чаще всего не нужны.
Когда lookahead НЕ нужен
Ситуация 1: символ реально должен входить в совпадение
Задача: найти cat!
Можно просто:
cat!
Lookahead не нужен, потому что:
!— часть того, что мы ищем
Ситуация 2: условие можно выразить обычной логикой
Задача: число, за которым идёт px
Можно так:
\d+px
Lookahead не нужен, потому что:
pxреально должно быть частью совпадения
Ситуация 3: шаблон и так однозначен
Задача: корректное арифметическое выражение
Мы уже делаем:
число (операция число)*
Lookahead не нужен, потому что:
- структура сама запрещает неправильные случаи
Когда lookahead ТОЧНО нужен
Ситуация 1: нужно ПРОВЕРИТЬ символ, но НЕ забирать его
Задача: найти cat, если дальше стоит !, но сам ! не включать
❌ Без lookahead нельзя
✅ С lookahead:
cat(?=!)
Почему:
!нужен только как условие, а не как часть результата
Ситуация 2: “разрешено всё, КРОМЕ этого”
Задача: найти cat, если дальше НЕ стоит !
cat(?!!)
Это невозможно аккуратно выразить без негативной проверки.
Ситуация 3: обязательные условия “где-то внутри строки”
Классика — пароль:
Условия:
- минимум 8 символов
- есть хотя бы одна буква
- есть хотя бы одна цифра
❌ Без lookahead почти невозможно
✅ С lookahead:
^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$
Lookahead тут:
- проверяет наличие
- ничего не съедает
Когда lookahead спасает от “лишнего захвата”
Задача: выражение не должно продолжаться цифрой
... (?![0-4])
Без lookahead регулярка может:
- схватить часть большего числа
- “слипнуть” с соседними символами
Короткое правило про lookahead
Если символ нужен только для проверки, но не должен попадать в результат — нужен lookahead.
Если символ должен быть частью совпадения — lookahead не нужен.
Таблица “быстро вспомнить”
Группы
| Задача | Нужны группы |
|---|---|
| Просто найти фрагмент | ❌ |
| Вытащить части | ✅ |
| Повторить тот же текст | ✅ |
| Поменять местами при замене | ✅ |
Опережающие проверки
| Задача | Нужен lookahead |
|---|---|
| Символ входит в результат | ❌ |
| Символ только проверяется | ✅ |
| “Есть где-то дальше” | ✅ |
| “Нельзя, чтобы было дальше” | ✅ |
Финальная мысль (очень важная)
Регулярные выражения не нужно усложнять заранее.
Правильный подход:
- попробовать без групп и lookahead
- если:
- нужно помнить кусок → добавить группы
- нужно проверить условие “впереди” → добавить lookahead
Примеры
Пример 1: повторяющееся слово
Задача: найти двойные слова типа да да, hello hello
Регулярка:
(\w+)\s+\1
Пошагово:
(\w+)— берём слово и запоминаем\s+— пробел(ы)\1— снова то же слово
Пример 2: извлечь код вида AB-1234
Задача: вытащить отдельно “буквы” и “цифры”.
Регулярка:
([A-Z]{2})-(\d{4})
- группа 1: две буквы
- группа 2: четыре цифры
Пример 3: число, но НЕ после знака минус (негативный lookahead)
Допустим, есть текст: 5 -7 12 -3 100
Хотим найти только положительные числа, то есть числа, которые не начинаются с -.
Регулярка:
(?!-)\d+
Что происходит:
(?!-)— “прямо сейчас не должен стоять минус”\d+— затем берём цифры
Пример 4 (посложнее): пароль “должны быть буквы и цифры” (lookahead)
Задача: строка из букв/цифр длиной ≥ 8, и в ней обязательно есть хотя бы:
- одна буква
- одна цифра
Регулярка (классическая идея):
^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$
Пошагово:
^— начало строки(?=.*[A-Za-z])— “где-то дальше найдётся буква”(?=.*\d)— “где-то дальше найдётся цифра”[A-Za-z\d]{8,}— вся строка состоит только из букв/цифр, длина минимум 8$— конец строки
Lookahead здесь удобен тем, что он проверяет условия, но не “съедает” символы.
Финальный кейс
Суть задания
Файл состоит из:
- цифр
0,1,2,3,4 - знаков
+и-
Нужно найти самую длинную непрерывную часть строки, которая является корректным выражением:
- числа — целые неотрицательные
- нет двух знаков операций подряд
- нет ведущих нулей (то есть
01нельзя,0можно) - перед самым первым числом может стоять
+или-, но если это не число0(то есть-0и+0нельзя)
Шаг 1. Описываем “число без ведущих нулей”
Разрешённые цифры только 0..4.
Число может быть:
- либо ровно
0 - либо начинается с
1..4, дальше любые0..4
Шаблон числа:
(0|[1-4][0-4]*)
Шаг 2. Число “в начале выражения” (там можно поставить знак, но не перед 0)
В начале выражения разрешены варианты:
0[1-4][0-4]*+[1-4][0-4]*-[1-4][0-4]*
Шаблон первого числа:
(?:[+-][1-4][0-4]*|[1-4][0-4]*|0)
Обратите внимание:
0— отдельно- вариант с
[+-]разрешён только для чисел, начинающихся с1..4
Шаг 3. “Хвост” выражения: (операция + число) повторяется много раз
После первого числа можно много раз повторять:
- знак операции
+или- - затем число без ведущих нулей
Число “после операции” уже обычное: 0 или [1-4][0-4]*
Шаблон хвоста:
(?:[+-](?:0|[1-4][0-4]*))*
Итоговая регулярка для поиска корректных фрагментов
Соединяем “первое число” и “хвост”:
(?:[+-][1-4][0-4]*|[1-4][0-4]*|0)(?:[+-](?:0|[1-4][0-4]*))*
Почему это выполняет условия
- Два знака подряд невозможны, потому что после
+/-обязательно идёт число. - Ведущих нулей нет, потому что число либо
0, либо начинается с1..4. +0и-0в начале запрещены, потому что начальный блок[+-]...допускает только[1-4]..., а0идёт отдельной веткой без знака.
Где здесь применяются опережающие проверки (lookahead)
В самом решении можно обойтись и без них. Но если хочется “подстраховаться”, например, чтобы совпадение не обрывалось внутри числа, иногда добавляют проверки границ.
Например, “после выражения не должна сразу идти цифра”:
(?:...выражение...)(?![0-4])
Это полезно, если у вас есть риск схватить кусок, который является частью большего числа.
Как из этого получить ответ “максимальная длина”
Идея простая (в любом языке программирования):
- найти все совпадения этой регуляркой
- взять максимальную длину
Онлайн тренажеры по использованию регулярных выражений
Существует несколько ресурсов, где вы можете потренироваться в создании и использовании регулярных выражений.
- Regex101 (https://regex101.com/):
- Особенности:
- Интерактивная песочница для тестирования регулярных выражений.
- Объяснения шагов и сопоставлений.
- Возможность выбора разных флагов (например, регистронезависимость).
- Особенности:
- Regexr (https://regexr.com/):
- Особенности:
- Интерактивный редактор с примерами и объяснениями.
- Возможность сохранения и загрузки регулярных выражений.
- Поддержка разных флагов.
- Особенности:
- RegExPal (https://www.regexpal.com/):
- Особенности:
- Простой и понятный интерфейс для тестирования регулярных выражений.
- Встроенные примеры и шаблоны.
- Особенности:
- RegexOne (https://regexone.com/):
- Особенности:
- Интерактивные уроки по изучению регулярных выражений.
- Постепенно увеличивающаяся сложность задач.
- Особенности:
- Exercism.io (https://exercism.io/):
- Особенности:
- Платформа для онлайн-обучения программированию.
- Включает задачи, связанные с регулярными выражениями.
- Особенности:
- HackerRank (https://www.hackerrank.com/domains/tutorials/10-days-of-javascript):
- Особенности:
- Сайт с задачами и учебными материалами.
- Раздел «10 Days of JavaScript» включает в себя уроки по регулярным выражениям на JavaScript.
- Особенности:
- LeetCode (https://leetcode.com/):
- Особенности:
- Платформа для подготовки к собеседованиям в IT.
- Задачи по регулярным выражениям в различных языках программирования.
- Особенности:
Модуль re в Python
re — это модуль в Python, предоставляющий функциональность для работы с регулярными выражениями. Основные возможности, которые предоставляет этот модуль:
re.search(pattern, string, flags=0):- Поиск первого совпадения с шаблоном в строке.
- Возвращает объект с информацией о совпадении или
None, если совпадений нет.import re pattern = r'\d+' text = 'The price is $42.50' match = re.search(pattern, text) if match: print(f'Found: {match.group()}') else: print('No match')
re.match(pattern, string, flags=0):- Проверка совпадения шаблона только в начале строки.
- Возвращает объект с информацией о совпадении или
None, если совпадений в начале строки нет.import re pattern = r'\d+' text = '42 is the answer.' match = re.match(pattern, text) if match: print(f'Found at the beginning: {match.group()}') else: print('No match at the beginning')
re.findall(pattern, string, flags=0):- Поиск всех совпадений шаблона в строке.
- Возвращает список всех найденных совпадений.
import re pattern = r'\d+' text = 'There are 42 apples and 30 oranges.' matches = re.findall(pattern, text) print(f'Found: {matches}')
re.finditer(pattern, string, flags=0):- Поиск всех совпадений шаблона в строке.
- Возвращает итератор, который возвращает объекты с информацией о каждом совпадении.
import re pattern = r'\d+' text = 'There are 42 apples and 30 oranges.' matches_iter = re.finditer(pattern, text) for match in matches_iter: print(f'Found: {match.group()} at position {match.start()}')
re.sub(pattern, replacement, string, count=0, flags=0):- Замена совпадений шаблона в строке на указанную подстановку.
- Возвращает новую строку.
import re pattern = r'\d+' text = 'There are 42 apples and 30 oranges.' new_text = re.sub(pattern, 'X', text) print(f'Original: {text}') print(f'Replaced: {new_text}')
- Флаги:
- Флаги добавляют дополнительные опции к работе с регулярными выражениями. Например,
re.IGNORECASEделает поиск нечувствительным к регистру.import re pattern = r'apple' text = 'I like Apple and banana.' match = re.search(pattern, text, flags=re.IGNORECASE) if match: print(f'Found: {match.group()}') else: print('No match')
- Флаги добавляют дополнительные опции к работе с регулярными выражениями. Например,
Флаги в регулярках
В регулярных выражениях в Python можно использовать различные флаги (или опции), которые изменяют поведение регулярного выражения при выполнении операций поиска, сопоставления и замены. Несколько основных флагов, которые могут быть использованы:
- re.IGNORECASE (
re.I):- Делает регулярное выражение нечувствительным к регистру.
re.search('apple', 'Apple', re.IGNORECASE)
- Делает регулярное выражение нечувствительным к регистру.
- re.MULTILINE (
re.M):- Позволяет
^и$соответствовать началу и концу каждой строки, а не всей строке целиком.re.search('^start', 'start\nend', re.MULTILINE)
- Позволяет
- re.DOTALL (
re.S):- Позволяет
.соответствовать любому символу, включая символ новой строки\n.re.search('a.b', 'a\nb', re.DOTALL)
- Позволяет
- re.VERBOSE (
re.X):- Разрешает использование пробелов и комментариев внутри регулярного выражения для улучшения читаемости.
re.search(r''' \d+ # Цифры [a-z]+ # Слова ''', '42 apples', re.VERBOSE)
- Разрешает использование пробелов и комментариев внутри регулярного выражения для улучшения читаемости.
- re.ASCII (
re.A):- Делает регулярное выражение чувствительным к ASCII. Влияет на интерпретацию
\w,\b,\dи т. д.re.search(r'\w+', 'résumé', re.ASCII)
- Делает регулярное выражение чувствительным к ASCII. Влияет на интерпретацию
- re.UNICODE (
re.U):- Делает регулярное выражение чувствительным к Unicode. Влияет на интерпретацию
\w,\b,\dи т. д.re.search(r'\w+', 'résumé', re.UNICODE)
- Делает регулярное выражение чувствительным к Unicode. Влияет на интерпретацию
- re.LOCALE (
re.L):- Делает регулярное выражение зависимым от текущей локали. Влияет на интерпретацию
\w,\b,\dи т. д.re.search(r'\w+', 'résumé', re.LOCALE)
- Делает регулярное выражение зависимым от текущей локали. Влияет на интерпретацию
Эти флаги могут быть использованы в комбинациях, добавляя их вторым аргументом к функциям модуля re, таким как re.search(), re.match(), re.findall(), re.sub(), и так далее. Например, re.IGNORECASE | re.MULTILINE указывает одновременное использование флагов IGNORECASE и MULTILINE.
Примеры поиска с помощью re
Пример 1: Простой поиск:
import re
pattern = r'\d+' # Шаблон для поиска одной или более цифр
text = 'There are 42 apples and 30 oranges.'
match = re.search(pattern, text)
if match:
print(f'Found: {match.group()}')
else:
print('No match')
#Found: 42
Пример 2: Поиск нескольких совпадений и их перебор:
import re
pattern = r'\d+' # Шаблон для поиска одной или более цифр
text = 'There are 42 apples and 30 oranges.'
matches = re.findall(pattern, text)
print(f'Found: {matches}')
#Found: ['42', '30']
Пример 3: Работа с группами в найденных выражениях:
import re
pattern = r'(\d+) (\w+)' # Шаблон для поиска цифр, за которыми следует слово
text = 'There are 42 apples and 30 oranges.'
matches = re.finditer(pattern, text)
for match in matches:
print(f'Number: {match.group(1)}, Fruit: {match.group(2)}')
#Number: 42, Fruit: apples
#Number: 30, Fruit: oranges
Замена с помощью регулярных выражений
Пример 1: Полная замена
import re
pattern = r'\d+' # Шаблон для поиска одной или более цифр
text = 'There are 42 apples and 30 oranges.'
new_text = re.sub(pattern, 'X', text)
print(f'Original: {text}')
print(f'Replaced: {new_text}')
#Original: There are 42 apples and 30 oranges.
#Replaced: There are X apples and X oranges.
Пример 2: Замена нескольких совпадений
import re
pattern = r'\d+' # Шаблон для поиска одной или более цифр
text = 'There are 42 apples and 30 oranges.'
new_text = re.sub(pattern, 'X', text, count=2)
print(f'Original: {text}')
print(f'Replaced: {new_text}')
#Original: There are 42 apples and 30 oranges.
#Replaced: There are X apples and X oranges.
Пример 3: Замена с использованием групп
import re
pattern = r'(\d+) (\w+)' # Шаблон для поиска цифр, за которыми следует слово
text = 'There are 42 apples and 30 oranges.'
new_text = re.sub(pattern, r'\2-\1', text)
print(f'Original: {text}')
print(f'Replaced: {new_text}')
#Original: There are 42 apples and 30 oranges.
#Replaced: There are apples-42 and oranges-30.
Пример 4: Замена с использованием паттерна в тексте на который заменяется исходный текст
import re
pattern = r'\d+' # Шаблон для поиска одной или более цифр
text = 'There are 42 apples and 30 oranges.'
replacement_pattern = r'Number: \g<0>'
new_text = re.sub(pattern, replacement_pattern, text)
print(f'Original: {text}')
print(f'Replaced: {new_text}')
#Original: There are 42 apples and 30 oranges.
#Replaced: There are Number: 42 apples and Number: 30 oranges.
Используемые конструкции в паттернах замены
В паттернах replacement (замены) в регулярных выражениях используются специальные символы и конструкции для вставки значений, найденных в тексте.
Обратные ссылки на группы:
\1, \2, \3, ...: Обратные ссылки на захватывающие группы. Эти символы вставляют текст, найденный в соответствующей группе.import re pattern = r'(\d+) (\w+)' text = 'There are 42 apples.' # Замена на "Number: <цифры>" new_text = re.sub(pattern, r'Number: \1', text) print(new_text) #There are Number: 42 apples.
Группы по именам:
\g<name>: Обратная ссылка на захватывающую группу по имени.import re pattern = r'(?P<digits>\d+) (?P<fruit>\w+)' text = 'There are 42 apples.' # Замена на "Number: <цифры>" new_text = re.sub(pattern, r'Number: \g<digits>', text) print(new_text) #There are Number: 42 apples.
Литералы и текст:
- Любой текст, не являющийся спецсимволом или обратной ссылкой, вставляется в результирующий текст как есть.
import re pattern = r'(\d+) (\w+)' text = 'There are 42 apples.' # Замена на "Count: 1, Type: apples" new_text = re.sub(pattern, r'Count: 1, Type: apples', text) print(new_text) #There are Count: 1, Type: apples.
Примеры использования регулярных выражений в Python
Обработка логов
Дан файл access.log веб сервера nginx. Необходимо получить информацию о времени, ip адресе и запрашиваемом url при доступе к сайту.
Допустим, у вас есть файл access.log nginx с записями в формате:
127.0.0.1 - - [10/Jan/2024:12:30:45 +0000] "GET /page1 HTTP/1.1" 200 1234
192.168.1.1 - - [10/Jan/2024:12:31:15 +0000] "GET /page2 HTTP/1.1" 404 5678
В этом примере мы будем использовать регулярные выражения для извлечения времени доступа, IP адреса и URL доступа к сайту.
import re
# Определение шаблона для извлечения информации из записей access.log
log_pattern = re.compile(r'(?P<ip>\d+\.\d+\.\d+\.\d+) - - \[(?P<timestamp>[^\]]+)\] "(?P<method>[A-Z]+) (?P<url>[^"]+)" \d+ \d+')
# Открытие файла и чтение строк
with open('access.log', 'r') as file:
for line in file:
# Поиск совпадения в каждой строке
match = log_pattern.search(line)
if match:
# Извлечение информации из совпадения
ip_address = match.group('ip')
timestamp = match.group('timestamp')
method = match.group('method')
url = match.group('url')
# Вывод извлеченной информации
print(f'IP: {ip_address}, Time: {timestamp}, Method: {method}, URL: {url}')
В данном коде:
log_patternпредставляет собой регулярное выражение, составленное для извлечения информации из записей access.log.- Затем файл
access.logоткрывается, и каждая строка обрабатывается с использованием регулярного выражения. - Если совпадение найдено, информация извлекается и выводится на экран.
Метод re.compile() в модуле re в Python используется для компиляции регулярного выражения в объект регулярного выражения. Это может повысить производительность, если вы собираетесь использовать одно и то же регулярное выражение во многих местах кода, так как объект регулярного выражения может быть повторно использован.
Разбор html файла с помощью регулярных выражений
Обработка HTML с использованием регулярных выражений может быть не самым рекомендуемым способом, потому что HTML — это структурированный язык, и лучше всего использовать парсеры HTML для более надежной и безопасной обработки. Например, в Python часто используются библиотеки, такие как BeautifulSoup или lxml.
Тем не менее, если у вас есть конкретная задача и вы решаете использовать регулярные выражения.
import re
def process_html(html):
# Поиск тега <div> с классом class1
pattern = r'<div\s+class="class1"\s*>(.*?)</div>'
match = re.search(pattern, html, flags=re.DOTALL)
if match:
# Извлечение содержимого и атрибутов тега
div_content = match.group(1)
# Замена класса class1 на class2
modified_div = re.sub(r'class="class1"', 'class="class2"', match.group(0))
# Заменить весь блок <div> на модифицированный
modified_html = html.replace(match.group(0), modified_div)
return modified_html, div_content
else:
return html, None
# Пример HTML кода
html_code = '''
<html>
<body>
<div class="class1">
<p>This is some content inside the div.</p>
</div>
<div class="other-class">
<p>This is another div.</p>
</div>
</body>
</html>
'''
# Обработка HTML и получение результата
modified_html, div_content = process_html(html_code)
# Вывод результата
print("Modified HTML:")
print(modified_html)
print("\nExtracted Content from class1 div:")
print(div_content)
Обратите внимание, что этот код работает для простых случаев и может не быть устойчивым к сложной вложенной структуре HTML. Важно помнить о том, что использование регулярных выражений для обработки HTML может привести к непредсказуемым результатам в более сложных сценариях.
Задания на тренировку регулярных выражений в Python
Задания 1-5: Простые задачи
Задание 1. Поиск цифры в строке: Напишите регулярное выражение, которое находит первую цифру в строке.
Задание 2. Извлечение слова из кавычек: Напишите регулярное выражение, которое извлекает слово, заключенное в кавычки (например, «word»).
Задание 3. Проверка корректности email: Напишите регулярное выражение для проверки, является ли строка корректным email-адресом.
Задание 4. Поиск повторяющихся слов: Напишите регулярное выражение для поиска повторяющихся слов в строке.
Задание 5. Извлечение номера телефона: Напишите регулярное выражение, которое извлекает номер телефона из строки. Учтите различные форматы записи (например, (123) 456-7890 или 123-456-7890).
import re
# 1. Поиск цифры в строке
pattern_1 = r'\d'
result_1 = re.search(pattern_1, 'Hello123')
print(result_1.group())
# 2. Извлечение слова из кавычек
pattern_2 = r'"(\w+)"'
result_2 = re.search(pattern_2, 'This is a "word" in quotes.')
print(result_2.group(1))
# 3. Проверка корректности email
pattern_3 = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
email = 'user@example.com'
is_valid_email = re.match(pattern_3, email)
print(is_valid_email)
# 4. Поиск повторяющихся слов
pattern_4 = r'\b(\w+)\b\s+\1\b'
result_4 = re.search(pattern_4, 'This is a test test.')
print(result_4.group())
# 5. Извлечение номера телефона
pattern_5 = r'\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}'
phone_number = '123-456-7890'
result_5 = re.search(pattern_5, phone_number)
print(result_5.group())
Задания 6-10: Задачи средней сложности
Задание 6. Поиск HTML-тегов: Напишите регулярное выражение для поиска и извлечения всех HTML-тегов из строки.
Задание 7. Извлечение даты: Напишите регулярное выражение, которое извлекает дату в формате «DD/MM/YYYY» из строки.
Задание 8. Поиск слова с определенным количеством символов: Напишите регулярное выражение, которое находит все слова в строке, состоящие из 5 букв.
Задание 9. Разбор URL: Напишите регулярное выражение, которое разбирает URL и извлекает протокол, домен и путь.
Задание 10. Поиск IPv6-адреса: Напишите регулярное выражение для поиска IPv6-адреса в строке.
# Примеры для заданий 6-10
# 6. Поиск HTML-тегов
pattern_6 = r'<[^>]+>'
html_text = '<p>This is <b>bold</b> text.</p>'
result_6 = re.findall(pattern_6, html_text)
print(result_6)
# 7. Извлечение даты
pattern_7 = r'\b\d{2}/\d{2}/\d{4}\b'
text_with_dates = 'Date: 01/15/2022, Meeting on 03/20/2022'
result_7 = re.findall(pattern_7, text_with_dates)
print(result_7)
# 8. Поиск слова с определенным количеством символов
pattern_8 = r'\b\w{5}\b'
text_with_words = 'Hello world, Python is amazing!'
result_8 = re.findall(pattern_8, text_with_words)
print(result_8)
# 9. Разбор URL
pattern_9 = r'(?P<protocol>https?)://(?P<domain>[\w.-]+)/(?P<path>[\w/]*)'
url = 'https://www.example.com/path/to/page'
result_9 = re.match(pattern_9, url)
print(result_9.groupdict())
# 10. Поиск IPv6-адреса
pattern_10 = r'[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}'
ipv6_address = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
result_10 = re.search(pattern_10, ipv6_address)
print(result_10.group())
Индивидуальное и групповое обучение «Python Junior»
Если вы хотите научиться программировать на Python, могу помочь. Запишитесь на мой курс «Python Junior» и начните свой путь в мир ИТ уже сегодня!
Контакты
Для получения дополнительной информации и записи на курсы свяжитесь со мной:
Телеграм: https://t.me/Vvkomlev
Email: victor.komlev@mail.ru
Объясняю сложное простыми словами. Даже если вы никогда не работали с ИТ и далеки от программирования, теперь у вас точно все получится! Проверено десятками примеров моих учеников.
Гибкий график обучения. Я предлагаю занятия в мини-группах и индивидуально, что позволяет каждому заниматься в удобном темпе. Вы можете совмещать обучение с работой или учебой.
Практическая направленность. 80%: практики, 20% теории. У меня множество авторских заданий, которые фокусируются на практике. Вы не просто изучаете теорию, а сразу применяете знания в реальных проектах и задачах.
Разнообразие учебных материалов: Теория представлена в виде текстовых уроков с примерами и видео, что делает обучение максимально эффективным и удобным.
Понимаю, что обучение информационным технологиям может быть сложным, особенно для новичков. Моя цель – сделать этот процесс максимально простым и увлекательным. У меня персонализированный подход к каждому ученику. Максимальный фокус внимания на ваши потребности и уровень подготовки.
