RegExp • Регуля́рные выраже́ния (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэ́кспы или ре́гексы) — это формальный язык поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов (символов-джокеров, англ. wildcard characters). По сути это строкаобразец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска. • Функции для работы со строками с помощью регулярных выражений находятся в модуле по имени re (regular expressions) Для чего нужны регулярные выражения? Регулярные выражения применяют для: а) поиска подстроки, удовлетворяющей шаблону регулярного выражения, в строке. б) поиска и замены подстроки, удовлетворяющей шаблону регулярного выражения, в строке. в) проверки на соответствие заданной строки шаблону. г) извлечения подстроки, удовлетворяющей шаблону регулярного выражения, из строки. Создать откомпилированный шаблон регулярного выражения позволяет функция compile(). Функция имеет следующий формат: <Шаблон> = re.compile(<Регулярное выражение>[, <Модификатор>]) Перед строками, содержащими регулярные выражения, указан модификатор r. Иными словами, мы используем неформатированные строки. Если модификатор не указать, то все слеши необходимо будет экранировать. p = re.compile(r”^\w+$”) p = re.compile(“^\\w+$”) Специальные обозначения Символ Что обозначает “.” “^” “$” “*” Любой символ Начало строки Конец строки Повторение фрагмента 0 или более раз: «go*gle» соответствует ggle, gogle, google и др. То же, но хотя бы 1 раз Предыдущий фрагмент либо присутствует, либо отсутствует: «colou?r» соответствует и color, и colour Повторение предыдущего фрагмента от m до n раз m и более повторений не более n повторений Любой символ из набора в скобках Любой символ не из набора в скобках С помощью символа обратной косой черты можно отменять специальное значение следующего за ней символа, например «\ (» - соответствует «(» Соответствует символам справа или слева Скобки, внутри которых находится регулярное выражение “+” “?” “{m, n}” “{m,}” “{,n}” “[…]” “[^…]” “\” “|” “(…)” • Помимо специальных обозначений, в регулярном выражении только буквы и цифры могут входить в качестве самих себя. Для внесения других символов необходимо использовать обратную косую черту. Например, скобку можно задать как «\ (» • С регулярным выражением можно не только сопоставлять строки (подходит – не подходит), но и искать строки, удовлетворяющие регулярному выражению, в тексте. ____________ В таблице ниже приведены регулярные выражения и примеры сопоставимых с ними и не сопоставимых с ними строк Запись шаблона Примеры строк, удовлетворяющих шаблону Примеры строк, не удовлетворяю щих шаблону Примечание “.*” “любая строка” “[abc]+” “a”, “baba”, “abba” “ ”, “adidas” Непустая строка из символов a,b,c “[a-z]+” “aakkaa”, “zyx”, “code” Непустая строка из строчных латинских букв “[a-h] [1-8]” “e2”, “e4”, “h1” “ ”, “Abba”, “ADIDAS” “k1”, “h0”, “a” “^From: .*” “From: abc@mail.ru” “ From:nospam” “^[A-Z] [a-z]*$” “One”, “Name” “Two names”, “other” “A?B?C?” “”, “A”, “B”, “C”, “AB”, “AC”, “BC”, “ABC” “BA”, “AA”, “A?B?C?” Произвольное число раз повторяется определенный символ Координаты клетки шахматной доски Поле электронного письма Строка с записью одного слова латинскими буквами, с большой буквы В столбце примера приведены все строки, которые удовлетворяют шаблону Запись шаблона Примеры строк, удовлетворяющих шаблону Примеры строк, Примечание не удовлетворяющих шаблону “(яблоко | апельсин)” “яблоко”, “апельсин” “(1)”, “()”, “(12345)”, “\(111\)” Либо “яблоко”, либо “апельсин” “(яблоко | апельсин ) +” “яблоко ”, “апельсин яблоко апельсин ”, “апельсин ” “апелько”, “яблокоапельсин” Положительное число повторений регулярного выражения в скобках “(кис+) +” “кис”, “кискискис”, “кисссскисскисссссс” “киисс” “[^():,.-]+” “слова”, “слова и пробелы” “-”, “(скобки)”, “запятые” “кис” несколько раз с любым числом букв “с” на концах Все, кроме указанных после “^” знаков. Заметьте, что “-” может стоять только в конце “[…]”, чтобы обозначать саму себя «Жадные» выражения • Все квантификаторы являются «жадными». При поиске соответствия ищется самая длинная подстрока, соответствующая шаблону, и не учитываются более короткие соответствия. Рассмотрим это на примере. Получим содержимое всех тегов <b> вместе с тегами: >>> s = "<b>Text1</b>Text2<b>Text3</b>" >>> p = re.compile(r"<b>.*</b>", re.S) >>> p.findall(s) [‘<b>Text1</b>Text2<b>Text3</b>’] • Чтобы ограничить «жадность», необходимо после квантификатора указать символ ? >>> s = "<b>Text1</b>Text2<b>Text3</b>" >>> p = re.compile(r"<b>.*?</b>", re.S) >>> p.findall(s) [‘<b>Text1</b>’ , ‘<b>Text3</b>’] • Если необходимо получить содержимое без тегов, то нужный фрагмент внутри шаблона следует разместить внутри круглых скобок >>>s = "<b>Text1</b>Text2<b>Text3</b>" >>> p = re.compile(r"<b>(.*?)</b>", re.S) >>> p.findall(s) [‘Text1’ , ‘Text3’] • *? - «не жадный» («ленивый») эквивалент * • +? - «не жадный» («ленивый») эквивалент + • {n,}? - «не жадный» («ленивый») эквивалент {n,} Группы • () Простая группа с захватом. • (?: ) Группа без захвата. То же самое, но заключённое в скобках выражение не добавляется к списку захваченных фрагментов. Например, если требуется найти или «здравствуйте», или «здрасте», но не важно, какое именно приветствие найдено, можно воспользоваться выражением здра(?:сте|вствуйте). • (?= ) Группа с проверкой впереди (zero-width positive lookahead assertion). Продолжает поиск только если справа от текущей позиции в тексте находится заключённое в скобки выражение. При этом само выражение не захватывается. Например, говор(?=ить) найдёт «говор» в «говорить», но не «говорит». • К найденному фрагменту в круглых скобках внутри шаблона можно обратиться с помощью механизма обратных ссылок. \1 – порядковый номер круглых скобок >>> s = "<b>Text1</b>Text2<I>Text3</I>" >>> p = re.compile(r"<([a-z]+)>(.*?)</\1>", re.S | re.I) >>> p.findall(s) [(‘b’, ‘Text1’) , (‘I’, ‘Text3’)] Функции Для поиска первого совпадения с шаблоном предназначены следующие функции: match() – проверяет соответствие с началом сторки re.match(<Шаблон>, <Строка>[, <Модификатор>]) >>> p = r”[0-9]+” >>> print “Найдено” if re.match(p, “str123”) else “Нет” Нет >>> print “Найдено” if re.match(p, “123str”) else “Нет” Найдено >>> p = re.compile(r”[0-9]+”) >>> print “Найдено” if re.match(p, “123str”) else “Нет” Найдено search() – проверяет соответствие с любой частью строки re.search(<Шаблон>, <Строка>[, <Модификатор>]) >>> p = r”[0-9]+” >>> print “Найдено” if re.search(p, “str123”) else “Нет” Найдено >>> p = re.compile(r”[0-9]+”) >>> print “Найдено” if re.search(p, “str123”) else “Нет” Найдено Проверка e-mail на соответствие шаблону # -*- coding: cp1251 -*import re email = raw_input(“Введите e-mail: “) pe = r"^([a-z0-9_.-]+)@(([a-z0-9-]+\.)+[a-z]{2,6})$" p = re.compile(pe, re.I) m = p.search(email) if not m: print “E-mail не соответствует шаблону” else: print “E-mail”, m.group(0), “соответствует шаблону” print “ящик:”, m.group(1), “домен:”, m.group(2) Результат выполнения: Введите e-mail: unicross@mail.ru E-mail unicross@mail.ru соответствует шаблону ящик: unicross домен: mail.ru Для поиска всех совпадений с шаблоном предназначены следующие функции: findall() – ищет все совпадения с шаблоном re.findall(<Шаблон>, <Строка>[, <Модификатор>]) >>> p = r”[0-9]+” >>> re.findall(p, “1 2 3 4 5 6”) [‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’] >>> p = re.compile(r”[0-9]+”) >>> re.findall(p, “1 2 3 4 5 6”) [‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’] finditer() – аналогично функции findall(), но возвращает итератор, а не список. re.finditer(<Шаблон>, <Строка>[, <Модификатор>]) Получим содержимое между тегами: >>> p = re.compile(r”<b>(.+?)</b>”, re.I | re.S) >>> s = “<b>Text1</b>Text2<b>Text3</b>” >>> for m in re.finditer(p, s): print m.group(1) Text1 Text3 Для замены в строке с помощью регулярных выражений предназначены следующие функции и методы: sub() – ищет все совпадения с шаблоном и заменяет их указанным значением. Если совпадения не найдены, возвращается исходная строка. subn() – аналогичен sub(), но возвращает не строку, а кортеж из двух элементов – измененной строки и количества произведенных замен. re.subn(<Шаблон>, <Новый фрагмент или ссылка на функцию>, <Строка для замены>[, <Максимальное количество замен>]) >>> p = r”200[79]” >>> re.subn(p, “2001”, “2007, 2008, 2009, 2010”) (‘2001, 2008, 2001, 2010’, 2)