Поиск с регулярными выражениями
Содержание
- Регулярные выражения и их синтаксис
- Модуль стандартной библиотеки
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-тэгов и возвращает очищенный текст.