Регулярные выражения
Регулярные выражения
Регуля́рные выраже́ния (англ. regular expressions) — формальный язык, используемый в компьютерных программах, работающих с текстом, для поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов. Для поиска используется строка-образец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска.
Для начала давайте разберемся с правилами поиска нужной подстроки. В простейшем виде мы ищем подстроки совпадающие с введенным текстом.
|
Регулярное выражение |
Текст с найденными значениями |
|
рек |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
|
Регулярное выражение |
Текст с найденными значениями |
|
р.к |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
С помощью квадратных скобок можно перечислить варианты, которые могут находиться на одной позиции.
|
Регулярное выражение |
Текст с найденными значениями |
|
р[уа]к |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
|
Регулярное выражение |
Текст с найденными значениями |
|
ре[а-я] |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
Также важную роль играют шаблоны соответствующие позициям, а не символам. Шаблон \b соответствуют началу или концу слова, т.е. если поставить слева от буквы в шаблоне, то эта буква будет нам подходить только если прямо перед ней нет другой буквы, аналогично, если поставить справа от буквы, то эта буква нам будет подходить только если сразу после нее нет другой буквы.
|
Регулярное выражение |
Текст с найденными значениями |
|
\bрек |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
|
к\b |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
На контрасте с шаблоном выше \B является его полной противоположностью. Данный шаблон соответствует середине слова. Т.е. если его поставить слева от буквы, то она нам подойдет только если с нее не начинается слово, а если поставить справа от буквы, то она нам подойдет только если на нее не заканчивается слово.
|
Регулярное выражение |
Текст с найденными значениями |
|
\Bрек |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
|
к\B |
Ехал Грека через реку, видит — в реке рак Сунул Грека руку в реку, рак за руку — цап |
Список часто используемых шаблонов (для диапазонов также можно использовать частичные диапазоны так, например, диапазон [в-е] соответствует любой букве из списка в, г, д, е).
|
Способы записи |
Описание |
|
|
[A-Z] |
Заглавные латинские буквы |
|
|
[a-z] |
Строчные латинские буквы |
|
|
[0-9] |
\d |
Цифры |
|
[а-я] |
Русские строчные буквы за исключением ё |
|
|
[А-Я] |
Русские заглавные буквы за исключение |
|
|
[^0-9] |
\D |
Любой символ кроме цифры |
|
[^\n] |
. |
Любой символ кроме перехода на новую строку |
|
\s |
Любой пробельный символ (пробел, табуляция, перехода на новую строку) |
|
|
\S |
Любой непробельный символ (всё кроме \s) |
|
|
[А-Яа-яA-Za-z0-9_] |
\w |
Любая буква, любая цифра или нижнее подчеркивание |
|
[^А-Яа-яA-Za-z0-9_] |
\W |
Всё что угодно кроме буквы, цифры и нижнего подчеркивания (всё кроме \w) |
|
\b |
Начало или конец слова |
|
|
\B |
Не начало и не конец слова |
|
|
$ |
Конец строки |
|
Также мы можем указывать количество повторений с помощью квантификаторов. Количество повторений указывается в фигурных скобках.
- {n} - когда необходимо ровно n повторений;
- {n,m} - когда нужно от n до m повторений;
- {,m} - когда нужно не более m повторений;
- {n,} - когда нужно не менее n повторений.
|
Регулярное выражение |
Текст с найденными значениями |
Комментарий |
|
[а-я]{3} |
Ехал Грека через реку, видит — в реке рак |
Комбинации из трех строчных букв |
|
\b[а-я]{3}\b |
Ехал Грека через реку, видит — в реке рак |
Трехбуквенные слова из строчных букв |
|
\b[а-я]{1,3}\b |
Ехал Грека через реку, видит — в реке рак |
Слова состоящие из 1-3 строчных букв |
|
\b[а-я]{,4}\b |
Ехал Грека через реку, видит — в реке рак |
Слова состоящие из не более чем 4 строчных букв (этот шаблон еще найдет нам кучу пустых строк, но это не особо важно) |
|
\b[а-я]{4,}\b |
Ехал Грека через реку, видит — в реке рак |
Слова состоящие из 4 и более строчных букв |
|
\b[А-Я][а-я]{4}\b |
Ехал Грека через реку, видит — в реке рак |
Слова начинающиеся с прописной буквы, а далее содержащие 4 строчных буквы |
|
Регулярное выражение |
Текст с найденными значениями |
|
[а-я]{3,5} |
Ехал Грека через реку, видит — в реке рак |
|
[а-я]{3,5}? |
Ехал Грека через реку, видит — в реке рак |
Также есть синонимы к часто встречающимся квантификаторам.
|
Способы записи |
Описание |
|
|
{0,1} |
? |
0 или 1 символ |
|
{0,} |
* |
От 0 и больше вхождений |
|
{1,} |
+ |
От 1 и больше вхождений |
Квантификаторы применяются к последнему указному символу (ну или набору диапазонов в квадратных скобках). Но что если мы в некотором наборе символов хотим найти все цепочки вида ABABABAB..., т.е. состоящую из пар AB. Квантификатор нужно применить к группе значений AB. Так вот для группировки значений используются круглые скобки. Так регулярное выражение (AB){1,} находит все цепочки состоящие из пар AB.
|
Регулярное выражение |
Текст с найденными значениями |
|
(AB){1,} |
ABAAAABABABBABABBABABABABBABBAAAAABBAABABAAABBBBBA |
|
Регулярное выражение |
Текст с найденными значениями |
|
(A|BB)+ |
ABAAAABABABBABABBABABABABBABBAAAAABBAABABAAABBBBBA |
Внутри квадратных скобок при указании символов ] и \ их нужно экранировать, т.е. добавлять перед ними символ \. Например, для добавления символа круглой скобки, даже если он всего 1, рекомендуется использовать квадратные скобки, чтобы не задумываться об экранировании. Что касается экранирования и работы в python, чтобы это экранирование работало корректно рекомендация всегда писать r перед строкой шаблона.
Библиотека re
В python есть библиотека re для работы с регулярными выражениями. Здесь поговорим об одной функции из этой библиотеки - findall(pattern, string). Она возвращает все не пересекающиеся подстроки из строки string подходящие под шаблон pattern. Она возвращает так называемые match-объекты, в которых довольно много информации по отдельным группам из регулярного выражения, при этом если не было выделено ни одной группы, то возвращается буквально список подстрок совпавших с шаблоном pattern. Для того чтобы удобно было проходиться с помощью циклов по найденным подстрокам, есть общая рекомендация весь шаблон оборачивать в круглые скобки для того, чтобы всегда была эта самая общая группа, и можно было не задумываться есть она или нет.
Решим одну из 24ых задач с помощью этой библиотеки
Задание с сайта ФИПИ A9D03C
Текстовый файл состоит из символов, обозначающих прописные буквы латинского алфавита.
Определите максимальное количество идущих подряд символов, среди которых никакие две буквы из набора букв A, B и С (с учетом повторений) не записаны подряд.
Для выполнения этого задания следует написать программу.
Решение
Давайте составим регулярное выражение для того, чтобы из строки содержащий символы латинского алфавита нам подходил любой символ кроме ABC. [D-Z]. Ну а соответственно, чтобы походил любой символ из набора ABC - это непосредственно [ABC]. Теперь, нам либо попадаются символы из набора [D-Z] и это нам всегда подходит, либо нам попадается один символ из набора [ABC], и тогда сразу после него должен идти снова символ из набора [D-Z]. Запишем это в виде регулярного выражения. ([ABC][D-Z]|[D-Z]). Соответственно такая ситуация может повторяться любой количество раз ([ABC][D-Z]|[D-Z]){0,} или ([ABC][D-Z]|[D-Z])*. Ну и учитываем, что когда мы найдем неподходящую пару, то один первый элемент из этой пары мы должны будем все равно брать в найденную подстроку. Итого наше регулярное выражение выглядит как ([ABC][D-Z]|[D-Z])*[ABC]. Ну и теперь напишем код в котором найдем самую длинную подстроку подходящую под составленное регулярное выражение.
from re import *
f=open("1_24.txt")
st=f.readline()
matches=findall(r"(([ABC][D-Z]|[D-Z])*[ABC])",st)
res=0
for i in range(len(matches)):
res=max(res,len(matches[i][0]))
print(res)