Саммерфилд - Программирование на Python 3 (1077331), страница 122
Текст из файла (страница 122)
Наличие проверки на границу слова гарантирует, что первое слово в совпадении будет целым словом, в результате в этом тексте не будет найдено совпадений, и ничего не будет сохраняться, так как здесь нет повторяющихся слов. Аналогично, если предположить, что поиск выполняется в тексте «опе ап<( ап<( 1»»го )е1'в вау», то без последней проверки было бы найдено два совпадения и выполнено два сохранения: опе апв апп !ио 1е(' в вау. Опережающая проверка гарантирует, что второе слово в совпадении будет целым словом, в результате в этом тексте будет найдено одно совпадение и выполнено одно сохранение: опе апв апв !ио 1е!' в вау. Цикл Рог выполняет итерации по всем объектам совпадений, возвращаемых методом (1пс11ег(), и мы используем метод дгоср() для получения фрагментов текста, сохраненных в группах.
Точно так же мы могли бы использовать вызов д гозр(1) (хотя это было бы менее понятно тому, кто будет сопровождать такой программный код) — в этом случае нам потребовалось бы отказаться от применения именованной сохраняющей группы и использовать регулярное выражение (!и+)!в+11(2('1и). Следует также отметить, что в конце регулярного выражения вместо ( г! '!и) можно было бы использовать проверку на границу слова 1Ь.
Другим регулярным выражением, представленным выше, было регулярное выражение, отыскивающее имена файлов в тегах изображений в документах НТМ1.. Ниже показано, как при компиляции регулярного выражения можно добавить флаги, чтобы оно не было чувствительно к регистру символов, и поддерживается возможность вставлять комментарии: !ваде ге = ге.спврт1е(г""" <!яд!в» а начало тега Модуль для работы с регулярными выражениями [ >].? згс= (?я<сырте>["'])? (?Р<сюадв>[ "'>]и) (?(ацотв)(?Р=дцотв) [">] ? > Я другие атрибуты я начало атрибута згс в необязательная открывающая кавычка я имя файла изображения ) я закрывающая кавычка я другие атрибуты В конец твга гв.НЕВВОЗЕ) ге. 1ОЯОВЕСАЗЕ~ сааце Г>1вз = [] Гог юаСсп сп 1щацв гв.тспстСвг(Сехт 1щаде Г11вз.аррепс(щатсп.цгоцр( ): 'сюацв")) овг ьсщ12свхс(псщ1 техт).
Оег спаг Ггощ впсссу(щассл): соов = псщ1.впсысвз.пащв2соовро1пт,цвс(пасся,цгоыр(!), Охейер) гвсогп слг(соов) техт = ге.зць(г"<( †(о:.(Нп)*о-->", "", тсщ1 твхс) в! свхс = гвнюЬ(г"<[РРЦ >]*?(?!</)>", "1птп", свхс) я2 твхс = гв.зць(г"<[ >]*?>", "", техт) вз свхс = гв.зць(г?Зв(1оч);", 1аюьоа ю: слг(спс(щ.цгоцр(1))), свхс) свхс = гв.зць(г?В([А-7а-т]ч);", слаг ггощ впс!су, свхс) яб техт = ге.зць(г"'тп(?:[ 1хАО'сс]чсп)+", "Нп", свхс) яб гвсцгп ге.зць(г"'тп'!пи", "'тп'сп", свхс.зсг!р()) я? Первому регулярному выражению <) --(?: . (тп ) *? --> соответствуют комментарии НТМ[ч включая теги НТМЕ, вложенные в них. Функция ге. Зцб() замещает все найденные совпадения указанным текстом— просто удаляет совпадения, если в качестве замены используется пустая строка, как в данном случае.
(Имеется возможность определить Здесь мы снова использовали метод С!об!те г( ) для получения всех найденных совпадений и метод цгоцр() объектов совпадений — для извлечения сохраненного текста. Поскольку регистр символов имеет значение только для выражений 1вц и згс, мы могли бы отбросить флаг ге.1ОВОЯЕСАЗЕ и использовать выражения [11][йа][6ц] и [Зз][йг][СО]. Это сделало бы регулярное выражение более трудным для чтения, но, возможно, более быстрым, так как при поиске совпадений не будет требоваться преобразовывать его символы в верхний или нижний регистр.
Однако, скорее всего, разницу в скорости можно будет заметить только при обработке больших объемов текста. Одна из типичных задач заключается в том, чтобы взять документ в формате НТМ[. и вывести только обычный текст, содержащийся в нем. Естественно, это можно сделать с применением одного из парсеров, входящих в состав Рут)соп, но с помощью регулярных выражений можно создать очень простой инструмент.
Чтобы реализовать это, необходимо решить трн задачи; удалить все теги, заменить сущности символами, которые они представляют, и вставить пустые строки, отделяющие параграфы, Ниже приводится функция (взята из программы )тст(21ехс ру), которая делает зту работу: 544 Глава 12. Регулярные выражения максимальное количество совпадений, передав дополнительно целое число в виде последнего аргумента,) Обратите внимание, что здесь выполняется поиск совпадений минимальной длины, чтобы гарантировать, что в каждом удаляемом совпадении будет только один комментарий; в противном случае мы могли бы удалить все, что находится между началом первого комментария и концом последнего.
Функция ге. эьЬ() не принимает никаких флагов в виде аргументов, вследствие этого символ . в регулярном выражении означает <любой символ за исключением символа перевода строки», поэтому мы должны выполнять поиск . или 1л. Отыскивать эти совпадения следует с использованием оператора выбора, а не с помощью символьного класса, так как внутри символьных классов точка интерпретируется буквально — как символ точки. Как вариант в начало регулярного выражения можно было бы добавить флаг, например (7в)<1--. ° 2-->, или скомпилировать регулярное выражение с флагом ге. 00ТАЬЬ; в этом случае регулярное выражение можно было бы упростить до <1--.
*7-->. Второму регулярному выражению <(Рр)[">)*7(71</)> соответствуют открывающие теги параграфов (такие как <Р> или <р а11дл=селгег>). Соответствие начинается с символов <р (или <Р), далее могут следовать любые атрибуты (используется минимальный квантификатор) и, наконец, закрывающий символ > при условии, что ему не предшествует символ олеша / (выполняется негативная ретроспективная проверка), поскольку наличие этого символа могло бы указывать на закрывающий тег параграфа. Второй вызов функции ге.
иЬ() использует это регулярное выражение для замены каждого открывающего тега параграфа на два символа перевода строки (обычный способ разделения параграфов в простых текстовых файлах). Третьему регулярному выражению <(">)*7> соответствуют любые теги, и оно используется в третьем вызове функции ге. взЬ() для удаления всех остальных тегов.
Сущности НТМ1 — это способ определить символы, не входящие в набор АЯС11, с помощью символов АЯС11. Сущности могут записываться в двух формах: Алаве;, где лаяв — это имя символа, например, сущность асару; обозначает символ ©, и ИЬ(д(Га, где с(д(гв — это десятичные цифры, определяющие числовой код символа в кодировке Юникод, например, И165; обозначает символ в. Четвертый вызов функции ге. эзЬ() использует регулярное выражение И(~О+);, которому соответствуют числовые формы сущностей, а сами цифры сохраняются в группе 1.
Вместо фактического текста замены мы передаем лямбда-функцию. Когда функция ге. зьЬ() получает другую функцию, она будет вызывать ее для каждого найденного совпадения, передавая ей объект совпадения в виде единственного аргумента. Внутри лямбда-функции мы извлекаем цифры (в виде строки), преобразуем их в целое число с помощью встроенной функции ал1() и затем с помощью встроенной функции Модуль для работы с регулярными выражениями 545 спг() получаем символ Юникода с заданным числовым кодом. Возвращаемое значение функции (или, в случае использования лямбда-выражения, результат выражения) используется в качестве текста замены. Пятый вызов функции ге,впо() использует регулярное выражение а((А-1а-в]+);, которое сохраняет именованные сущности. Модуль 0Гв).
ел Г!Г1е в из стандартной библиотеки содержит словари сущностей, включая пвве2сооеро1пт, ключами которого являются имена сущностей, а значениями — целочисленные коды символов. Функция ге. вп0( ) вызывает локальную функцию сПвг ( гоа еп(ату() всякий раз, когда обнаруживает совпадение. Функция спвг ггоз епЫГу() использует метод 01сГ.Ое(() со значением ОхЕЕЕО аргумента, используемым по умолчанию (код символа Юникода, обычно используемого для замены и часто изображаемого как 9). Это гарантирует получение кода символа и передачу его функции спг(), которая вернет соответствующий символ для замены именованной сущности, — с использованием предопределенного символа Юникода для замены неопознанной сущности. Регулярное выражение ~п(7: ( ~хАО~т]+~п)+ в шестом вызове функции ге.вз0() используется для удаления строк, содержащих только пробельные символы.
Используемый здесь символьный класс содержит пробел, неразрывный пробел (представляемый сущностью йпввр;, которая будет замещена предыдущим регулярным выражением) и символ табуляции. Регулярному выражению соответствует символ перевода строки (предшествующей одной или более строкам, состоящим только из пробельных символов) и по меньшей мере одна строка (или более, благодаря максимальному квантификатору), состоящая только из пробельных символов. Поскольку совпадение включает в себя символ перевода строки из строки, предшествующей строкам из пробельных символов, необходимо заменить совпадение одиночным символом перевода строки; в противном случае будут удалены не только пробельные строки, но н символ перевода строки из предшествующей им строки.
Результат седьмого и последнего вызова функции ге. зпо() возвращается вызывающей программе. Данное регулярное выражение ~п~п+ используется для замены последовательностей из двух и более символов перевода строки точно двумя символами перевода строки, чтобы гарантировать, что параграфы будут отделяться друг от друга только одной пустой строкой. В этом примере ни одна из замещающих строк не была взята непосредственно из совпадения (впрочем, здесь использовались именованные и числовые сущности НТМЬ), но в некоторых ситуациях может возникнуть необходимость включить в строку замены весь текст совпадения или его часть.