Опубликован: 14.06.2015 | Уровень: для всех | Доступ: платный
Самостоятельная работа 11:

Регулярные выражения

< Самостоятельная работа 1 || Самостоятельная работа 11: 12345

23.2. Извлечение данных с помощью регулярных выражений

Для выделения данных из строки Питон предоставляет метод findall(), извлекающий все подстроки, соответствующие регулярному выражению. Пусть мы хотим извлечь всё, что похоже на адрес электронной почты, из любой строки, независимо от ее формата. Например, мы хотим извлечь e-mail адрес из любой из следующих строк:

From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008
Return-Path: <postmaster@collab.sakaiproject.org>
for <source@collab.sakaiproject.org>;
Received: (from apache@localhost)
Author: stephen.marquard@uct.ac.za
  

Не хотелось бы писать отдельный код для каждого типа строк, разбирая по-своему каждую строку. Приведенная ниже программа использует метод findall() для нахождения всех строк с e-mail адресом и извлечения одного или нескольких адресов из таких строк.

import re
s = 'Hello from csev@umich.edu to cwen@iupui.edu about the meeting @2PM'
lst = re.findall('\S+@\S+', s)
print lst
  

Метод findall() производит поиск регулярного выражения в строке, переданной ему в качестве второго аргумента, и возвращает список всех ее подстрок, которые выглядят как e-mail адреса. Мы используем специальную двухсимвольную последовательность \S длины 2, которая сопоставляется любому непробельному (non-whitespace) символу. На выходе программы получим:

['csev@umich.edu', 'cwen@iupui.edu']

Сопоставляя регулярное выражение, мы находим все подстроки, имеющие хотя бы один непробельный символ, за которым следует символ @, после которого в свою очередь идет один или более непробельный символ. Шаблон "\S+" аналогично сопоставляется максимально длинной последовательности непробельных символов (это называют "жадным" поведением в регулярных выражениях).

Регулярное выражение сопоставляется дважды (csev@umich.edu и cwen@iupui.edu), но оно не соответствует подстроке "@2PM", поскольку перед символом @ нет непробельных символов. Мы можем использовать это регулярное выражение в программе, читающей все строки в файле и печатающей всё, что выглядит как e-mail адрес:

import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
x = re.findall('\S+@\S+', line)
if len(x) > 0 :
print x
  

Из каждой прочитанной строки извлекаются все подстроки, соответствующие нашему регулярному выражению. Поскольку метод findall() возвращает список, достаточно проверить, что число его элементов больше нуля, чтобы напечатать строки, содержащие e-mail адреса.

Применив программу к файлу mbox.txt, получим следующий результат:

['wagnermr@iupui.edu']
['cwen@iupui.edu']
['<postmaster@collab.sakaiproject.org>']
['<200801032122.m03LMFo4005148@nakamura.uits.iupui.edu>']
['<source@collab.sakaiproject.org>;']
['<source@collab.sakaiproject.org>;']
['<source@collab.sakaiproject.org>;']
['apache@localhost)']
['source@collab.sakaiproject.org;']
  

Некоторые из этих e-mail адресов содержат некорректные символы "<" или ";" в начале либо конце. Укажем, что нас интересует лишь часть строки, начинающаяся и заканчивающаяся буквой или цифрой. Для этого используем другую возможность, предоставляемую регулярными выражениями. Квадратные скобки в них применяются для указания множества допустимых символов, используемых при сопоставлении. В этом смысле шаблон "\S" соответствует множеству всех непробельных символов. Теперь мы более явно укажем множество сопоставляемых символов.

Вот наше новое регулярное выражение:

[a-zA-Z0-9]\S*@\S*[a-zA-Z]

Оно несколько сложнее, теперь уже видно, почему регулярные выражения можно считать самостоятельным языком. Данное регулярное выражение означает, что мы ищем подстроки, начинающиеся с одиночной строчной буквы, прописной буквы или цифры "[a-zA-Z0-9]", за которой следует ноль или более непробельных символов "\S*", дальше идет символ @, потом ноль или более непробельных символов "\S*" и в конце строчная или прописная буква. Отметим, что мы заменили "+ " на "* " для указания нуля или более непробельных символов, поскольку фрагмент " [a-zA-Z0-9] " уже представляет собой один непробельный символ.

Помните, что "* " или "+ " применяются к одному символу, стоящему непосредственно слева от звездочки или плюса. Если мы используем это выражение в нашей программе, выходные данные будут более чистыми:

import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
x = re.findall('[a-zA-Z0-9]\S+@\S+[a-zA-Z]', line)
if len(x) > 0 :
print x
['wagnermr@iupui.edu']
['cwen@iupui.edu']
['postmaster@collab.sakaiproject.org']
['200801032122.m03LMFo4005148@nakamura.uits.iupui.edu']
['source@collab.sakaiproject.org']
['source@collab.sakaiproject.org']
['source@collab.sakaiproject.org']
['apache@localhost']
  

Отметим, что из строк, содержащих фрагмент "source@collab.sakaiproject.org", наше регулярное выражение исключило два символа в конце строки (">;"). Это произошло потому, что, добавив фрагмент "[a-zA-Z]" в конец нашего регулярного выражения, мы указали, что подстрока, которая сопоставляется регулярному выражению, обязательно должна заканчиваться буквой. Поэтому сопоставление заканчивается, как только мы доходим до символа ">" в конце "sakaiproject.org>;" – на последней "сопоставимой" букве (в данном случае "g"). Также отметим, что каждая строчка вывода программы представляет собой одноэлементный список Питона, единственным элементом которого является строка.

< Самостоятельная работа 1 || Самостоятельная работа 11: 12345
Алексей Виноградов
Алексей Виноградов

Видеокурс выложен на сайте Altube.ru вместо Youtube и плеер Altube не поддерживает субтитры. Прошу решить вопрос о предоставлении русских субтитров в этом англоязычном видеокурсе.

Петр Олейников
Петр Олейников

Данные файлы неоходимы не только для самостоятельных работ, но и для тестов. А по ссылкам в лекциях они не доступны, выдает ошибку 404.

Александр Душечкин
Александр Душечкин
Россия, Ижевск, ИжГТУ, 2002
Дмитрий Голиков
Дмитрий Голиков
Россия