Программирование на Python 3. Руководство издательство СимволПлюс
Скачать 3.74 Mb.
|
• Проверка: проверка соответствия фрагментов текста некоторым критериям, например, наличие символа обозначения валюты и по следующих за ним цифр. • Поиск: поиск подстрок, которые могут иметь несколько форм, на пример, поиск подстрок «pet.png», «pet.jpg», «pet.jpeg» или «pet.svg», чтобы при этом не обнаруживались подстроки «car pet.png» и подобные ей. • Поиск и замена: замена всего, что совпадает с регулярным выраже нием, и замена на указанную строку, например, поиск подстроки 1 Существует превосходная книга о регулярных выражениях: Jeffrey E. F. Friedl «Mastering Regular Expressions» (Джеффри Фридл «Регуляр ные выражения», 3е издание. – Пер. с англ. – СПб.: СимволПлюс, 2008). Она не имеет явного отношения к языку Python, но модуль re, входящий в состав Python, предлагает функциональность, во многом похожую на ту, что предлагается механизмом регулярных выражений языка Perl, кото рый подробно рассматривается в этой книге. • Язык регулярных выражений в Python • Модуль для работы с регулярными выражениями Язык регулярных выражений в Python 525 «устройство передвижения, движимое мускульной силой» и заме на подстрокой «велосипед». • Разбиение строк: разбиение строки по точкам совпадения с регу лярным выражением, например, разбиение строки по подстроке «: » или «=». Самым простым выражением является выражение (например, обыч ный символ), за которым может следовать квантификатор. Более сложные регулярные выражения могут состоять из любого числа вы ражений с квантификаторами и могут включать проверки и дополни тельные флаги. В первом разделе этой главы будут представлены и описаны все ключе вые концепции, имеющие отношение к регулярным выражениям, и будет продемонстрирован чистый синтаксис регулярных выражений с минимальными ссылками на язык Python. Затем, во втором разделе, будет показано, как использовать регулярные выражения в контексте программирования на языке Python, с привлечением сведений из пре дыдущих разделов. Читатели, знакомые с регулярными выражения ми и желающие узнать, как они работают в языке Python, могут сразу перейти ко второму разделу (на стр. 538). Глава полностью охватывает язык регулярных выражений, предлагаемый модулем re, включая все проверки и флаги. Мы будем выделять регулярные выражения в тек сте жирным шрифтом, места совпадений – шрифтом с подчеркиванием, а захва ченные символы – Язык регулярных выражений в Python В этом разделе мы разобьем рассмотрение языка регулярных выраже ний на четыре подраздела. В первом подразделе демонстрируется, как находить совпадения с отдельными символами или с группами симво лов, например, совпадение с символом a, или совпадение с символом b, или совпадение с символом a или b. Во втором подразделе демонстри руется, как находить совпадения с применением квантификаторов, например, единственное совпадение, или не менее одного совпадения, или столько совпадений, сколько вообще возможно. В третьем подраз деле демонстрируется, как группировать подвыражения и как сохра нять текст совпадений. И, наконец, в последнем подразделе демонст рируется, как воздействовать на работу регулярных выражений с ис пользованием проверок и флагов. Символы и классы символов Простейшее регулярное выражение – это обычные литералы симво лов, такие как a или 5. В отсутствие явного квантификатора такое вы ражение подразумевает «совпадение с одним вхождением». Напри мер, регулярное выражение tune состоит из четырех выражений, каж дое из них неявно определяет одно совпадение, поэтому оно будет сов с подчеркиванием и затенением 526 Глава 12. Регулярные выражения падать с одним символом t, за которым следует один символ u, за которым следует один символ n, за которым следует один символ e, то есть оно будет совпадать со строками tune и attuned. Большинство символов могут использоваться как лите ралы, но некоторые из них имеют «специальное назначе ние» в языке регулярных выражений и потому должны экранироваться символом обратного слеша (\), когда они используются как литералы. К специальным относятся символы \.^$?+*{}[]()|. В пределах регулярных выраже ний можно также использовать большинство стандарт ных экранированных последовательностей языка Py thon, например, \n – для обозначения символа перевода строки, \t – для обозначения символа табуляции, а так же экранированные последовательности с шестнадцате ричными кодами символов \xHH, \uHHHH и \UHHHHHHHH. Во многих случаях вместо совпадения с единственным символом быва ет необходимо отыскать совпадение с одним из множества символов. Реализовать это можно с помощью символьного класса – один или бо лее символов, заключенные в квадратные скобки. (Символьные клас сы не имеют никакого отношения к классам в языке Python – это про сто термин регулярных выражений, используемый для обозначения «множества символов».) Символьный класс – это выражение и, как и любое другое выражение, в отсутствие явного квантификатора соот ветствует точно одному символу (который может быть любым симво лом из данного символьного класса). Например, регулярное выраже ние r[ea]d совпадает с red и radar, но не со словом read. Точно так же, чтобы отыскать совпадение с единственной цифрой, можно использо вать регулярное выражение [0123456789]. Для удобства можно указы вать диапазон символов с помощью символа дефиса; так, выражение [0 9] также будет соответствовать цифре. Имеется возможность инвер тировать значение символьного класса, указывая символ «крышки» после открывающей квадратной скобки; так, выражение [^0 9] будет соответствовать любому символу, но не цифре. Обратите внимание, что в символьном классе все специальные симво лы, кроме символа \, теряют свое специальное значение, но, что каса ется символа ^, то он приобретает новое значение (инверсия), когда яв ляется первым символом в символьном классе; в противном случае он просто обозначает символ «крышки». Кроме того, символ дефиса обо значает диапазон символов, только если он не является первым симво лом – в этом случае он просто обозначает символ дефиса. Так как некоторые наборы символов требуются достаточно часто, для них предусматриваются краткие формы записи – они перечислены в табл. 12.1. За одним исключением, эти сокращенные формы могут использоваться внутри символьных классов, например, регулярное выражение [\dA Fa f] соответствует шестнадцатеричной цифре. Ис Экранирован ные последо вательности, стр. 86 Язык регулярных выражений в Python 527 ключение составляет символ точки, который за пределами символьно го класса обозначает набор символов, а внутри символьного класса – сам символ точки. Таблица 12.1. Сокращенные формы символьных классов Квантификаторы Квантификаторы записываются в виде {m,n}, где m и n – это минималь ное и максимальное число совпадений с выражением, при которых со ответствие выражению с квантификатором будет считаться найден ным. Например, оба выражения e{1,1}e{1,1} и e{2,2} соответствуют слову feel, но не соответствуют слову felt. Записывать квантификатор после каждого выражения было бы слиш ком утомительно, а сами регулярные выражения при этом было бы трудно читать. К счастью, язык регулярных выражений поддержива ет несколько удобных сокращений. Если в квантификаторе указыва ется только одно число, оно обозначает и минимум и максимум, то есть выражение e{2} – это то же самое, что выражение e{2,2}. И, как уже отмечалось в предыдущем разделе, если квантификатор не указан явно, предполагается, что он равен единице (например, {1,1}, или {1}), то есть выражение ee – это то же самое, что выражение e{1,1}e{1,1} или e{1}e{1}; оба выражения e{2} и ee соответствуют слову feel, но не соответствуют слову felt. Бывает удобно использовать различные минимальное и максимальное значения. Например, чтобы найти совпадение со словами travelled и traveled (обе формы записи являются допустимыми) можно было бы Символ Значение . Соответствует любому символу, за исключением символа перевода строки, или любому символу, если используется флаг re.DOTALL, или символу . внутри символьного класса \d Соответствует цифре Юникода или [0 9], если используется флаг re.ASCII \D Соответствует нецифровому символу Юникода или [^0 9], если используется флаг re.ASCII \s Соответствует любому пробельному символу Юникода или [ \t\n\r\f\v] , если используется флаг re.ASCII \S Соответствует любому символу Юникода, не являющемуся про бельным, или [^ \t\n\r\f\v], если используется флаг re.ASCII \w Соответствует символу «слова» Юникода или [a zA Z0 9_], если используется флаг re.ASCII \W Соответствует любому символу не«слова» Юникода или [^a zA Z0 9_] , если используется флаг re.ASCII Флаги, стр. 533 528 Глава 12. Регулярные выражения использовать выражение travel{1,2}ed или travell{0,1}ed. Квантифи катор {0,1} используется настолько часто, что для него появилось соб ственное сокращение – ?; поэтому другой способ записи (к тому же ча ще использующийся на практике) этого регулярного выражения вы глядит так: travell?ed. Имеются еще два сокращения для квантификаторов: + – обозначает {1,n} («не менее одного»); * – обозначает {0,n} («любое число»). В обоих случаях n обозначает максимально допустимое для квантификатора число, которое обычно не менее 32 767. Все квантификаторы перечис лены в табл. 12.2. Таблица 12.2. Квантификаторы регулярных выражений Квантификатор + очень удобен. Например, для поиска соответствий целым числам можно было бы использовать выражение \d+, так как оно совпадает с одной или более цифрами. Данное регулярное выра жение может отыскать два совпадения в строке 4588.91, например, Синтаксис Значение e? или e{0,1} Максимальный, соответствует нулевому или большему чис лу вхождений выражения e e?? или e{0,1}? Минимальный, соответствует нулевому или большему чис лу вхождений выражения e e+ или e{1,} Максимальный, соответствует одному или больше вхожде нию выражения e e+? или e{1,}? Минимальный, соответствует одному или больше вхожде нию выражения e e* или e{0,} Максимальный, соответствует нулевому или большему чис лу вхождений выражения e e*? или e{0,}? Минимальный, соответствует нулевому или большему чис лу вхождений выражения e e{m} Соответствует точно m вхождениям выражения e e{m,} Максимальный, соответствует по меньшей мере m вхожде ниям выражения e e{m,}? Минимальный, соответствует по меньшей мере m вхождени ям выражения e e{,n} Максимальный, соответствует не более чем n вхождениям выражения e e{,n}? Минимальный, соответствует не более чем n вхождениям выражения e e{m,n} Максимальный, соответствует не менее чем m и не более чем n вхождениям выражения e e{m,n}? Минимальный, соответствует не менее чем m и не более чем n вхождениям выражения e Язык регулярных выражений в Python 529 4588.91 и 4588.91. Иногда длительное удержание клавиши приводит к появлению опечаток. Мы могли бы использовать выражение bevel+ed для поиска допустимых форм написания beveled и bevelled, а также опечатки bevellled. Если бы потребовалось считать допустимой только форму записи с одним символом l и отыскать только формы записи с двумя или более символами l, мы могли бы применить регулярное выражение bevell+ed. Квантификатор * используется реже – просто потому, что он может приводить к получению неожиданных результатов. Например, пред положим, что требуется отыскать строки с комментариями в файлах с программным кодом на языке Python. Для этого мы могли бы попы таться использовать регулярное выражение #*. Но такое выражение будет соответствовать любым строкам, даже пустым, потому что фраза «совпадение с любым числом символов #» подразумевает и нулевое число совпадений. Если вы плохо знакомы с регулярными выраже ниями, возьмите себе за правило вообще не использовать квантифика тор *, а если вы используете его (или квантификатор ?), то обязательно убедитесь, что хотя бы одно подвыражение в регулярном выражении использует ненулевой квантификатор, то есть используется хотя бы один квантификатор, отличный от * и ?, так как оба они могут нахо дить соответствие при нулевом числе совпадений. Часто возможно заменить квантификатор * на квантификатор +, и на оборот. Например, отыскать соответствие слову «tasselled», в котором присутствует хотя бы один символ l, можно с помощью выражения tassell*ed или tassel+ed, а соответствие формам записи с двумя или бо лее символами l – с помощью tasselll*ed или tassell+ed. Регулярное выражение \d+ будет соответствовать строке 136. Но поче му оно соответствует всем цифрам, а не только первой? По умолчанию все квантификаторы являются жадными (или максимальными) – они стремятся соответствовать как можно большему числу символов. Лю бой квантификатор можно сделать нежадным (или минимальным), до бавив после него символ ?. (Знак вопроса имеет два разных значения – когда он употребляется самостоятельно, он интерпретируется как со кращенная форма записи квантификатора {0,1}, а когда следует за квантификатором – он говорит о том, что стоящий перед ним кванти фикатор является минимальным.) Например, выражение \d+? обнару жит соответствие в строке 136 в трех разных местах: 136, 136 и 136. Дру гое выражение: \d?? соответствует нулевому или большему числу цифр, но предпочтение будет отдано нулевому числу совпадений, по тому что используется минимальный квантификатор – он порождает ту же проблему, что и квантификатор *, и может находить соответст вие «с ничем», то есть будет соответствовать вообще любому тексту. Минимальные квантификаторы могут с успехом использоваться для быстрого и приблизительного синтаксического анализа документов в формате XML и HTML. Например, для поиска всех тегов изображе 530 Глава 12. Регулярные выражения ний можно было бы использовать выражение «m», затем символ «g», затем ноль или более любых символов, за ис ключением символа перевода строки, и затем символ «>»), но оно бу дет давать неверные результаты, потому часть .* является жадной и будет соответствовать всему подряд, включая закрывающую угло вую скобку тега «>», и остановится только по достижении последнего символа «>» в тексте. Сами собой напрашиваются три варианта решения (кроме использова ния нормального парсера). Одно из них – выражение ]*> (соот ветствует подстроке волов, отличных от >, и затем следует закрывающая угловая скобка тега >), другое – выражение , затем следует >) и третье решение является комбинацией двух пре дыдущих – ]*?>. Но ни одно из них не является правильным, потому что все они будут соответствовать строке , которая не яв ляется допустимым тегом. Так как известно, что тег изображения дол жен иметь атрибут src, можно записать более точное регулярное выра жение ]*?src=\w+[^>]*?>. Это выражение соответствует всем литералам символов бельных символов, затем минимально ноль или более любых симво лов, за исключением > (чтобы пропустить любые атрибуты, такие как alt ), затем атрибут src (символы src=, затем хотя бы один символ «сло ва»), затем любой (включая нулевое число) символ, за исключением >, чтобы пропустить любые другие атрибуты, и, наконец, закрывающая угловая скобка >. Группировка и сохранение На практике часто бывают необходимы регулярные выражения, соот ветствующие любой из двух или более альтернатив, и нередко требует ся сохранить совпадение или какуюто его часть для последующей об работки. Кроме того, иногда требуется, чтобы квантификатор приме нялся к нескольким выражениям. Все это может быть реализовано с помощью операции группировки (), а выбор альтернативных вари антов можно реализовать с помощью конструкции выбора |. Конструкция выбора особенно удобна, когда необходимо отыскать сов падение с одной из нескольких альтернатив. Например, регулярное выражение aircraft|airplane|jet будет соответствовать любому тексту, содержащему «aircraft», «airplane» или «jet». Тот же результат мож но получить с помощью регулярного выражения air(craft|plane)|jet. В данном случае круглые скобки используются для группировки вы ражений, таким образом здесь имеются два внешних выражения: |