Поиск с регулярными выражениями
Содержание
- Регулярные выражения и их синтаксис
- Модуль стандартной библиотеки
re
и функцииre.search
- Домашнее задание
Регулярные выражения и их синтаксис
Регулярные выражения (RE, regexp) нужны, чтобы находить в строках подстроки не по точному вхождению, а описываемые правилами-шаблонами.
! Если нужно найти точное вхождение, лучше использовать стандартные методы строк, а не re
.
Специальные символы, с помощью которых мы будем задавать правила поиска строк:
.
один любой символ?
0 или 1 вхождение предыдущего символа*
предыдущий символ повторяется ≥ 0 раз (0, 1, 2, 3 и т. д.)+
предыдущий символ повторяется ≥ 1 раз (1, 2, 3 и т. д.)^
начало строки$
конец строки[abc]
«или»: любой из символов а, b, c[а-я]
любая буква русского алфавита от «а» до «я» Внутри квадратных скобок большинство специальных символ не действуют:.
обозначает точку,?
— вопросительный знак. Вне квадратных скобок, чтобы получить точку или, например, плюс, специальные символы надо экранировать с помощью\
(\.
обозначает точку,\+
обозначает плюс).[^abc]
— отрицание: любой символ, кроме a, b, c.\d
любая цифра, аналогично[0-9]
\D
— любой символ, кроме цифр (отрицание\d
или[^0-9]
)\w
— буквы, цифры,_
(то же, что[a-zA-Z0-9_]
),\W
— всё кроме букв, цифр,_
.\s
— любой пробелоподбный символ ([ \t\n\r\f\v]
),\S
— любой непробелоподбный символ
Регулярные выражения в питоне
Мы будем использовать модуль re
:
import re
Функция re.search(pattern, string)
возвращает первое вхождение подстроки, которая подходит под регулярное выражение. Обратите внимание на порядок аргументов: первый — это регулярное выражение, второй — исходная строка, в которой мы ищем.
first_match = re.search('кот.', 'Кот пришёл к коту и спросил кота: «Бойкот, котелок или скотч?»')
re.search
возвращает объект match
(или None
, если ничего не нашлось), из которого затем можно извлечь результат методом group()
:
if first_match:
first_match.group() # 'кот '
else:
print('Nothing found.')
Ещё одна полезная функция re.findall(pattern, string)
находит все вхождения подходящих строк:
all_results = re.findall('кот.', 'кот пришёл к коту и спросил кота: «Бойкот, котелок или скотч?»')
all_results # ['кот ', 'коту', 'кота', 'кот,', 'коте', 'котч']
“Сырые” (raw) строки
Для регулярных выражений в питоне лучше использовать синтаксис для «сырых» (raw) строк. Если добавить r
в начале строки (r'\d'
), то питон будет обрабатывать эту строку не как обычную, а как сырую.
Зачем это нужно? В регулярных выражениях для экранирования специальных символов используется \
– например, \.
обозначает точку, \+
– плюс, и т. д. Но когда питон читает обычные, не “сырые” строки (ещё до того, как мы с этой строкой что-то сделали), он тоже использует \
для экранирования символов, но по-другому (например \n
– это перенос строки, \t
– табуляция, а \\
– буквально символ \
). Из-за различий в правилах экранирования может возникнуть путаница – например, при попытке обработать строку \d
как обычную, не как “сырую”, питон выдаст синтаксическую ошибку, потому что он не знает, во что преобразовать \d
. Другой пример – в синтаксисе регулярных выражений \b
обозначает границу слова, а в синтаксисе питоновских строк – символ backspace (поэтому, когда мы не используем “сырые” строки, \b
преобразуется в backspace).
Предположим, нам нужно написать регулярное выражение, соответствующее подстроке \section
. В синтаксисе регулярных выражений оно будет выглядеть так: \\section
(символ \
должен быть экранирован). Но, если мы не используем “сырые” строки, то нам придётся записать его как \\\\section
– оба символа \
должны быть экранированы ещё раз, чтобы питон их правильно прочитал. Довольно неудобно.
В “сырых” строках питон ничего не экранирует, а \
читается как обычный символ и экранируется только в регулярном выражении, поэтому путаницы не возникает. Например, на print('Hello!\nHi!')
мы получим
Hello!
Hi!
a на print(r'Hello!\nHi!')
–
Hello!\nHi!
Соответственно, “сырая” строка с регулярным выражением для поиска подстроки \section
будет выглядеть просто как r'\\section'
.
Кроме того, “сырые” строки удобно использовать для хранения пути к файлам в Windows (например r'C:\Documents\myfile.txt'
), так как там тоже используется \
.
Ограничение: “сырые” строки не могут содержать нечётное количество символов \
в конце.
Найдем все числа в строке:
digits_list = re.findall(r'\d', 'Я родился 30 февраля 1930 года')
digits_str = ''.join(digits) # '301930'
Домашнее задание
Задача для всех вариантов – написать 10 функций, использующих регулярные выражения. Решение не должно содержать в себе ничего, кроме функций. Для того, чтобы удалять из текста подстроки, соответствующие определённому паттерну, воспользуйтесь функцией re.sub
.
Скелет программы для работы вот такой:
def phone_num_validation(string):
pass
def date_validation(string):
pass
def roman_num_validation(string):
pass
def ipv4_validation(string):
pass
def whitespace_cleaning(filename):
pass
def named_entitites_counter(filename):
pass
def numbering_cleaning(filename):
pass
def loanwords_extraction(filename):
pass
def html_tag_extraction(filename):
pass
def html_tag_cleaning(filename):
pass
Первые 4 функции принимают на вход строку и возвращают True
или False
в зависимости от того, является ли строка:
- номером мобильного телефона формата +7 (9ХХ) ХХХ-ХХ-ХХ
- датой формата DD.MM.YYYY в диапазоне от 1000 до 1999 года включительно
- числом в римской системе счисления
- валидным IPv4 адресом в десятичной с точками форме записи (например,
127.0.0.1
)
Следующие 4 функции принимают на вход название текстового файла с русским текстом в кодировке UTF-8 и:
- удаляет из текста все лишние пробелы и переносы строк – заменяет все последовательности из двух и более пробелов или переносов строк на один пробел или перенос строки соотвественно, и возвращает очищенный текст.
- возвращает частотный словарь (воспользуйтесь классом
collections.Counter
) всех словоформ имён собственных, кроме тех, которые стоят в начале предложения - удаляет из текста нумерацию глав и возвращает очищенный текст. Нумерацией глав считать любые арабские или римские числа, находящиеся на отдельной строке (после числа может стоять одна точка).
- возвращает список заимствований в тексте. Заимствованиями считать любые последовательности букв латинского алфавита (кроме римских цифр), разделённых пробелами и переносами строк (примеры из тестового текста:
'Hollywood Canteen'
,'Black and Tan Fantasy'
). Подсказка: пользуйтесь функциями, написанными ранее.
Последние 2 функции принимают на вход название HTML-файла в кодировке UTF-8 и:
- возвращает список всех HTML-тэгов.
- чистит текст файла от HTML-тэгов и возвращает очищенный текст.