Spec-Zone.ru › Python 3.5

re — Операции с регулярными выражениями

Исходный код: Lib/re.py

Этот модуль предоставляет операции сопоставления с регулярными выражениями, аналогичные тем, что есть в Perl.

И шаблоны, и строки, которые нужно искать, могут быть строками Unicode, а также строками 8-битных символов. Однако строки Unicode и 8-битные строки не могут быть смешаны: то есть вы не можете сопоставить строку Unicode с байтовым шаблоном или наоборот; аналогично, когда вы запрашиваете подстановку, строка замены должна быть того же типа, что и шаблон и строка поиска.

В регулярных выражениях используется обратная косая черта ('\') для указания специальных форм или для разрешения использования специальных символов без вызова их специального значения. Это вступает в конфликт с использованием Python того же символа для той же цели в строковых литералах; например, чтобы сопоставить литеранльную обратную косую черту, можно написать '\\\\' в качестве строки шаблона, потому что регулярное выражение должно быть \\, и каждая обратная косая черта должна быть выражена как \\ внутри обычной строки Python.

Решение заключается в использовании синтаксиса сырых строк Python для шаблонов регулярных выражений; обратные косые черты не обрабатываются каким-либо специальным образом в строковом литерале с префиксом 'r'. Таким образом, r"\n" — это строка из двух символов, содержащая '\' и 'n', в то время как "\n" — это строка из одного символа, содержащая перевод строки. Обычно шаблоны будут выражаться в коде Python с использованием этого синтаксиса сырых строк.

Важно отметить, что большинство операций с регулярными выражениями доступны как функции и методы на уровне модуля в скомпилированных регулярных выражениях. Функции являются сокращениями, которые не требуют компиляции объекта regex, но пропускают некоторые параметры тонкой настройки.

См. также

Модуль сторонних разработчиков regex, который имеет API, совместимый со стандартным модулем re, но предлагает дополнительные функции и более тщательную поддержку Unicode.

1. Синтаксис регулярных выражений

Регулярное выражение (или RE) определяет множество строк, которые ему соответствуют; функции в этом модуле позволяют проверить, соответствует ли определенная строка данному регулярному выражению (или соответствует ли данное регулярное выражение определенной строке, что сводится к одному и тому же).

Регулярные выражения могут быть конкатенированы для формирования новых регулярных выражений; если A и B — оба регулярные выражения, то AB также является регулярным выражением. В общем случае, если строка p соответствует A, а другая строка q соответствует B, то строка pq будет соответствовать AB. Это верно, если A или B не содержат операций низкого приоритета; граничные условия между A и B; или имеют ссылок на нумерованные группы. Таким образом, сложные выражения легко конструируются из более простых примитивных выражений, описанных здесь. Для подробностей о теории и реализации регулярных выражений обратитесь к книге Фридла, упомянутой выше, или любой учебник по построению компиляторов.

Следует краткое объяснение формата регулярных выражений. Для получения дополнительной информации и более мягкой презентации см. Руководство по регулярным выражениям.

Регулярные выражения могут содержать как специальные, так и обычные символы. Большинство обычных символов, такие как 'A', 'a', или '0', являются простейшими регулярными выражениями; они просто соответствуют самим себе. Вы можете конкатенировать обычные символы, так что last соответствует строке 'last'. (В остальной части этого раздела мы будем писать RE в this special style, обычно без кавычек, а строки для сопоставления 'in single quotes'.)

Некоторые символы, такие как '|' или '(', являются специальными. Специальные символы либо представляют классы обычных символов, либо влияют на то, как интерпретируются регулярные выражения вокруг них. Строки шаблонов регулярных выражений не могут содержать нулевые байты, но могут указывать нулевой байт с использованием обозначения \number, такого как '\x00'.

Квалификаторы повторения (*, +, ?, {m,n}, и т. д.) не могут быть вложены непосредственно. Это предотвращает неоднозначность с постфиксом модификатора жадного соответствия ?, и с другими модификаторами в других реализациях. Для применения второго повторения к внутреннему повторению могут использоваться скобки. Например, выражение (?:a{6})* соответствует любому кратному шести 'a' символам.

Специальные символы:

'.'
(Точка.) В режиме по умолчанию, соответствует любому символу, кроме новой строки. Если флаг DOTALL был указан, соответствует любому символу, включая новую строку.
'^'
(Знак возведения в степень.) Соответствует началу строки и в режиме MULTILINE также соответствует сразу после каждой новой строки.
'$'
Соответствует концу строки или непосредственно перед новой строкой в конце строки, а в режиме MULTILINE также соответствует перед новой строкой. foo соответствует как «foo», так и «foobar», тогда как регулярное выражение foo$ соответствует только «foo». Более интересно, поиск foo.$ в 'foo1\nfoo2\n' соответствует «foo2» обычно, но «foo1» в режиме MULTILINE; поиск одиночного $ в 'foo\n' найдет две (пустые) совпадения: одно непосредственно перед новой строкой и одно в конце строки.
'*'
Приводит к тому, что результирующее регулярное выражение соответствует 0 или более повторениям предыдущего регулярного выражения, столько повторений, сколько возможно. ab* будет соответствовать «a», «ab» или «a», за которым следует любое количество «b».
'+'
Приводит к тому, что результирующее регулярное выражение соответствует 1 или более повторениям предыдущего регулярного выражения. ab+ будет соответствовать «a», за которым следует любое ненулевое количество «b»; оно не будет соответствовать только «a».
'?'
Приводит к тому, что результирующее регулярное выражение соответствует 0 или 1 повторению предыдущего регулярного выражения. ab? будет соответствовать либо «a», либо «ab».
*?, +?, ??
Квалификаторы '*', '+', и '?' являются жадными; они соответствуют как можно большему количеству текста. Иногда это поведение нежелательно; если регулярное выражение <.*> соответствует <a> b <c>, оно будет соответствовать всей строке, а не только <a>. Добавление ? после квалификатора заставляет его выполнять сопоставление в нежадном или минимальном режиме; будет сопоставлено как можно меньше символов. Используя регулярное выражение <.*?> будет соответствовать только <a>.
{m}
Указывает, что должно быть сопоставлено ровно m копий предыдущего регулярного выражения; меньше совпадений приводят к тому, что все регулярное выражение не соответствует. Например, a{6} будет соответствовать ровно шести символам 'a', но не пяти.
{m,n}
Приводит к тому, что результирующее регулярное выражение соответствует от m до n повторений предыдущего регулярного выражения, пытаясь сопоставить как можно больше повторений. Например, a{3,5} будет соответствовать от 3 до 5 символов 'a'. Пропуск m задает нижнюю границу 0, а пропуск n задает бесконечную верхнюю границу. Например, a{4,}b будет соответствовать aaaab или тысяче символов 'a' за которым следует b, но не aaab. Запятую нельзя опустить, иначе модификатор будет спутано с ранее описанной формой.
{m,n}?
Приводит к тому, что результирующее регулярное выражение соответствует от m до n повторений предыдущего регулярного выражения, пытаясь сопоставить как можно меньше повторений. Это нежадная версия предыдущего квалификатора. Например, для 6-символьной строки 'aaaaaa', a{3,5} будет соответствовать 5 символам 'a', в то время как a{3,5}? будет соответствовать только 3 символам.
'\'

Или экранирует специальные символы (позволяя вам соответствовать таким символам, как '*', '?', и так далее), или сигнализирует о специальной последовательности; специальные последовательности описаны ниже.

Если вы не используете строку без символа «r» для выражения шаблона, помните, что Python также использует обратную косую черту в качестве escape-последовательности в строковых литералах; если escape-последовательность не распознается парсером Python, обратная косая черта и последующий символ включаются в результирующую строку. Однако, если Python распознает получившуюся последовательность, обратная косая черта должна повторяться дважды. Это сложно и трудно понять, поэтому настоятельно рекомендуется использовать строки без символа «r» для всех, кроме самых простых выражений.

[]

Используется для указания набора символов. В наборе:

  • Символы могут быть перечислены индивидуально, например, [amk] будет соответствовать 'a', 'm', или 'k'.
  • Диапазоны символов могут быть указаны, указав два символа и разделив их дефисом, например, [a-z] будет соответствовать любой строчной букве ASCII, [0-5][0-9] будет соответствовать всем двузначным числам от 00 до 59, а [0-9A-Fa-f] будет соответствовать любой шестнадцатеричной цифре. Если - экранирован (например, [a\-z]) или если он помещен в качестве первого или последнего символа (например, [a-]), он будет соответствовать буквально '-'.
  • Специальные символы теряют свое специальное значение внутри наборов. Например, [(+*)] будет соответствовать любому из буквальных символов '(', '+', '*', или ')'.
  • Классы символов, такие как \w или \S (определены ниже), также принимаются внутри набора, хотя символы, которым они соответствуют, зависят от того, включен ли режим ASCII или LOCALE.
  • Символы, которые не входят в диапазон, могут быть сопоставлены с помощью дополнения набора. Если первым символом набора является '^', все символы, которые не находятся в наборе, будут сопоставлены. Например, [^5] будет соответствовать любому символу, кроме '5', а [^^] будет соответствовать любому символу, кроме '^'. ^ не имеет специального значения, если это не первый символ в наборе.
  • Для соответствия буквально ']' внутри набора, предваряйте его обратной косой чертой или поместите его в начало набора. Например, и [()[\]{}] и []()[{}] оба будут соответствовать скобке.
'|'
A|B, где A и B могут быть произвольными регулярными выражениями, создает регулярное выражение, которое будет соответствовать либо A, либо B. В этом случае может быть указано любое количество регулярных выражений, разделенных символом '|'. Это также может быть использовано внутри групп (см. ниже). По мере сканирования целевой строки регулярные выражения, разделенные '|', пытаются соответствовать слева направо. Когда один шаблон полностью соответствует, эта ветвь принимается. Это означает, что как только A соответствует, B больше не будет проверяться, даже если бы это привело к более длинному совпадению в целом. Другими словами, оператор '|' никогда не является жадным. Для соответствия буквально '|', используйте \|, или заключите его в набор символов, как в [|].
(...)
Соответствует тому регулярному выражению, которое находится внутри скобок, и указывает начало и конец группы; содержимое группы может быть получено после выполнения сопоставления и может быть сопоставлено позже в строке с помощью специальной последовательности \number, описанной ниже. Для соответствия буквально '(' или ')', используйте \( или \), или заключите их в набор символов: [(] [)].
(?...)
Это расширение обозначения ('?' после '(' не имеет другого смысла). Первый символ после '?' определяет смысл и дальнейшую синтаксическую конструкцию. Расширения обычно не создают новую группу; (?P<name>...) — единственное исключение из этого правила. Ниже приведены поддерживаемые расширения.
(?aiLmsux)

(Одна или несколько букв из набора 'a', 'i', 'L', 'm', 's', 'u', 'x'.) Группа соответствует пустой строке; буквы устанавливают соответствующие флаги: re.A (только ASCII-совпадение), re.I (игнорировать регистр), re.L (зависит от локали), re.M (многострочный), re.S (точка соответствует всем) и re.X (подробный) для всего регулярного выражения. (Флаги описаны в Содержание модуля.) Это полезно, если вы хотите включить флаги в часть регулярного выражения вместо передачи аргумента флага функции re.compile().

Обратите внимание, что флаг (?x) изменяет способ парсинга выражения. Он должен быть использован первым в строке выражения или после одного или нескольких пробелов. Если перед флагом есть не-пробельные символы, результаты не определены.

(?:...)
Незахватывающая версия обычных скобок. Соответствует тому регулярному выражению, которое находится внутри скобок, но подстрока, к которой соответствует группа, не может быть извлечена после выполнения сопоставления или ссылаться на нее позже в шаблоне.
(?P<name>...)

Аналогично обычным круглым скобкам, но подстрока, соответствующая группе, доступна через символическое имя группы name. Имена групп должны быть допустимыми идентификаторами Python, и каждое имя группы должно быть определено только один раз в регулярном выражении. Символическая группа также является пронумерованной группой, так же как если бы группа не имела имени.

Имена групп могут быть использованы в трех контекстах. Если шаблон (?P<quote>['"]).*?(?P=quote) (т. е. соответствие строке, заключённой в одинарные или двойные кавычки):

Контекст ссылки на группу “quote” Способы ссылки на неё
в самом шаблоне
  • (?P=quote) (как показано)
  • \1
при обработке объекта совпадения m
  • m.group('quote')
  • m.end('quote') (и т. д.)
в строке, переданной в аргумент repl функции re.sub()
  • \g<quote>
  • \g<1>
  • \1
(?P=name)
Ссылка на именованную группу; она соответствует тексту, который был сопоставлен ранее именованной группе name.
(?#...)
Комментарий; содержимое скобок просто игнорируется.
(?=...)
Совпадает, если ... соответствует следующему, но не потребляет никакой части строки. Это называется утверждением о предстоящем совпадении. Например, Isaac (?=Asimov) будет соответствовать 'Isaac ' только в том случае, если за ним следует 'Asimov'.
(?!...)
Совпадает, если ... не соответствует следующему. Это утверждение о предстоящем несовпадении. Например, Isaac (?!Asimov) будет соответствовать 'Isaac ' только в том случае, если за ним не следует 'Asimov'.
(?<=...)

Совпадает, если текущая позиция в строке предшествует совпадению с ..., которое заканчивается в текущей позиции. Это называется утверждением о предшествующем совпадении. (?<=abc)def найдет совпадение в abcdef, так как lookbehind отступит на 3 символа и проверит, соответствует ли вложенный шаблон. Вложенный шаблон должен соответствовать только строкам фиксированной длины, что означает, что abc или a|b разрешены, но a* и a{3,4} не разрешены. Обратите внимание, что шаблоны, начинающиеся с утверждений о предшествующих совпадениях, не будут соответствовать началу искомой строки; скорее всего, вам захочется использовать функцию search(), а не функцию match():

>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

Этот пример ищет слово, за которым следует тире:

>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

Изменено в версии 3.5: Добавлена поддержка ссылок на группы фиксированной длины.

(?<!...)
Совпадает, если текущая позиция в строке не предшествует совпадению с .... Это называется утверждением о предшествующем несовпадении. Подобно утверждениям о предшествующих совпадениях, содержащийся шаблон должен соответствовать только строкам фиксированной длины. Шаблоны, начинающиеся с утверждений о предшествующих несовпадениях, могут соответствовать началу искомой строки.
(?(id/name)yes-pattern|no-pattern)
Попытается найти совпадение с yes-pattern, если группа с заданным идентификатором или именем существует, и с no-pattern в противном случае. no-pattern является необязательным и может быть опущено. Например, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) — плохой шаблон для соответствия адресам электронной почты, который будет совпадать с '<user@host.com>' и 'user@host.com', но не с '<user@host.com' ни с 'user@host.com>'.

Специальные последовательности состоят из '\' и символа из нижеследующего списка. Если обычный символ отсутствует в списке, то результирующее регулярное выражение будет соответствовать второму символу. Например, \$ соответствует символу '$'.

\number
Соответствует содержимому группы с тем же номером. Группы нумеруются, начиная с 1. Например, (.+) \1 соответствует 'the the' или '55 55', но не 'thethe' (обратите внимание на пробел после группы). Эта специальная последовательность может быть использована только для соответствия одной из первых 99 групп. Если первая цифра number равна 0, или number представляет собой 3 восьмеричных цифры, то она не будет интерпретироваться как соответствие группе, а как символ с восьмеричным значением number. Внутри '[' и ']' класса символов все числовые эскейпы обрабатываются как символы.
\A
Совпадает только в начале строки.
\b

Соответствует пустой строке, но только в начале или конце слова. Слово определяется как последовательность Unicode-алфавитно-цифровых символов или символов подчеркивания, поэтому конец слова указывается пробелом или неалфавитно-цифровым, не содержащим символов подчеркивания, Unicode-символом. Обратите внимание, что формально \b определяется как граница между \w и \W символами (или наоборот), или между \w и началом/концом строки. Это означает, что r'\bfoo\b' соответствует 'foo', 'foo.', '(foo)', 'bar foo baz', но не 'foobar' или 'foo3'.

По умолчанию используются Unicode-алфавитно-цифровые символы, но это можно изменить, используя флаг ASCII. Внутри диапазона символов \b представляет символ удаления, для совместимости с строковыми литералами Python.

\B
Соответствует пустой строке, но только тогда, когда она не находится в начале или конце слова. Это означает, что r'py\B' соответствует 'python', 'py3', 'py2', но не 'py', 'py.', или 'py!'. \B — это просто обратное \b, поэтому символы слов — это Unicode-алфавитно-цифровые символы или символ подчеркивания, хотя это можно изменить, используя флаг ASCII.
\d
Для шаблонов Unicode (str):
Соответствует любой Unicode-десятичной цифре (то есть любому символу в категории Unicode-символов [Nd]). Включает [0-9], а также многие другие символы цифр. Если используется флаг ASCII, соответствует только [0-9] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [0-9] может быть лучшим вариантом).
Для шаблонов 8-битных (bytes):
Соответствует любой десятичной цифре; это эквивалентно [0-9].
\D
Соответствует любому символу, который не является Unicode-десятичной цифрой. Это противоположность \d. Если используется флаг ASCII, это становится эквивалентом [^0-9] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [^0-9] может быть лучшим вариантом).
\s
Для шаблонов Unicode (str):
Соответствует Unicode-пробелам (включая [ \t\n\r\f\v], а также многие другие символы, например, неразрывные пробелы, предписанные правилами типографики во многих языках). Если используется флаг ASCII, соответствует только [ \t\n\r\f\v] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [ \t\n\r\f\v] может быть лучшим вариантом).
Для шаблонов 8-битных (bytes):
Соответствует символам, рассматриваемым как пробелы в ASCII-кодировке; это эквивалентно [ \t\n\r\f\v].
\S
Соответствует любому символу, который не является Unicode-пробелом. Это противоположность \s. Если используется флаг ASCII, это становится эквивалентом [^ \t\n\r\f\v] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [^ \t\n\r\f\v] может быть лучшим вариантом).
\w
Для шаблонов Unicode (str):
Соответствует символам Unicode-слов; это включает большинство символов, которые могут быть частью слова на любом языке, а также цифры и символ подчеркивания. Если используется флаг ASCII, соответствует только [a-zA-Z0-9_] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [a-zA-Z0-9_] может быть лучшим вариантом).
Для шаблонов 8-битных (bytes):
Соответствует символам, рассматриваемым как алфавитно-цифровые в ASCII-кодировке; это эквивалентно [a-zA-Z0-9_].
\W
Соответствует любому символу, который не является Unicode-символом слова. Это противоположность \w. Если используется флаг ASCII, это становится эквивалентом [^a-zA-Z0-9_] (но флаг влияет на всё регулярное выражение, поэтому в таких случаях использование явного [^a-zA-Z0-9_] может быть лучшим вариантом).
\Z
Совпадает только в конце строки.

Большинство стандартных эскейпов, поддерживаемых строковыми литералами Python, также принимаются парсером регулярных выражений:

\a      \b      \f      \n
\r      \t      \u      \U
\v      \x      \\

(Обратите внимание, что \b используется для представления границ слов и означает «удаление» только внутри классов символов.)

'\u' и '\U' последовательности эскейпов распознаются только в Unicode-шаблонах. В шаблонах байтов они не обрабатываются особо.

Восьмеричные эскейпы включены в ограниченной форме. Если первая цифра равна 0, или если есть три восьмеричных цифры, она рассматривается как восьмеричный эскейп. В противном случае это ссылка на группу. Как и в строковых литералах, восьмеричные эскейпы всегда имеют длину не более трёх цифр.

Изменено в версии 3.3: Добавлены escape-последовательности '\u' и '\U'.

Устарело начиная с версии 3.5, будет удалено в версии 3.6: Неизвестные escape-последовательности, состоящие из '\' и символов ASCII, теперь вызывают предупреждение об устаревании и будут запрещены в Python 3.6.

См. также

Изучение регулярных выражений
Книга о регулярных выражениях Джеффри Фридла, опубликованная издательством O’Reilly. Второе издание книги больше не охватывает Python, но первое издание подробно рассказывало о написании хороших шаблонов регулярных выражений.

2. Содержание модуля

Модуль определяет несколько функций, констант и исключение. Некоторые функции являются упрощенными версиями полных методов для скомпилированных регулярных выражений. Большинство нетривиальных приложений всегда используют скомпилированную форму.

re.compile(pattern, flags=0)

Компилирует шаблон регулярного выражения в объект регулярного выражения, который можно использовать для сопоставления с помощью его методов match() и search(), описанных ниже.

Поведение выражения можно изменить, указав значение flags. Значения могут быть любыми из следующих переменных, объединенных с помощью побитового ИЛИ (оператора |).

Последовательность

prog = re.compile(pattern)
result = prog.match(string)

эквивалентна

result = re.match(pattern, string)

но использование re.compile() и сохранение полученного объекта регулярного выражения для повторного использования более эффективно, когда выражение будет использоваться несколько раз в одной программе.

Примечание

Скомпилированные версии последних шаблонов, переданных в re.compile() и функции сопоставления на уровне модуля, кэшируются, поэтому программам, использующим лишь несколько регулярных выражений, не нужно беспокоиться о компиляции регулярных выражений.

re.A
re.ASCII

Заставить \w, \W, \b, \B, \d, \D, \s и \S выполнять сопоставление только ASCII вместо полного сопоставления Unicode. Это имеет смысл только для шаблонов Unicode и игнорируется для байтовых шаблонов.

Обратите внимание, что для обратной совместимости флаг re.U (а также его синоним re.UNICODE и его встроенный аналог (?u)) по-прежнему существует, но они избыточны в Python 3, так как сопоставления по умолчанию являются Unicode для строк (и сопоставление Unicode не разрешено для байтов).

re.DEBUG

Отобразить отладочную информацию о скомпилированном выражении.

re.I
re.IGNORECASE

Выполнить регистронезависимое сопоставление; выражения, такие как [A-Z], также будут соответствовать строчным буквам. Это не зависит от текущей локали и работает для символов Unicode, как ожидается.

re.L
re.LOCALE

Сделать \w, \W, \b, \B, \s и \S зависящими от текущей локали. Использование этого флага не рекомендуется, так как механизм локали очень ненадежен, и он обрабатывает только одну «культуру» за раз; следует использовать сопоставление Unicode, которое по умолчанию используется в Python 3 для Unicode (строк). Этот флаг имеет смысл только для байтовых шаблонов.

Устарело начиная с версии 3.5, будет удалено в версии 3.6: Устарел use of re.LOCALE со строковыми шаблонами или re.ASCII.

re.M
re.MULTILINE

При указании символ шаблона '^' соответствует началу строки и началу каждой строки (непосредственно после каждого символа новой строки); и символ шаблона '$' соответствует концу строки и концу каждой строки (непосредственно перед каждым символом новой строки). По умолчанию '^' соответствует только началу строки, а '$' — только концу строки и непосредственно перед символом новой строки (если таковой имеется) в конце строки.

re.S
re.DOTALL

Заставляет специальный символ '.' соответствовать любому символу, включая символ новой строки; без этого флага '.' будет соответствовать любому символу, *кроме* символа новой строки.

re.X
re.VERBOSE

Этот флаг позволяет писать более удобочитаемые регулярные выражения, позволяя визуально разделять логические части шаблона и добавлять комментарии. Пробелы внутри шаблона игнорируются, за исключением случаев, когда они находятся в классе символов или когда предваряются неэкранированным обратным слэшем. Когда строка содержит #, который не находится в классе символов и не предваряется неэкранированным обратным слэшем, все символы слева от такого # до конца строки игнорируются.

Это означает, что следующие два объекта регулярных выражений, которые соответствуют десятичному числу, функционально равны:

a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
re.search(pattern, string, flags=0)

Просматривает строку в поисках первого местоположения, где регулярное выражение шаблон дает совпадение, и возвращает соответствующий объект объект совпадения. Возвращает None если ни одна позиция в строке не соответствует шаблону; обратите внимание, что это отличается от поиска совпадения нулевой длины в какой-то точке строки.

re.match(pattern, string, flags=0)

Если ноль или более символов в начале строки соответствуют регулярному выражению шаблон, возвращает соответствующий объект объект совпадения. Возвращает None если строка не соответствует шаблону; обратите внимание, что это отличается от совпадения нулевой длины.

Обратите внимание, что даже в режиме MULTILINE, re.match() будет соответствовать только началу строки, а не началу каждой строки.

Если требуется найти совпадение где угодно в строке, используйте search() (см. также search() vs. match()).

re.fullmatch(pattern, string, flags=0)

Если вся строка соответствует регулярному выражению шаблон, возвращает соответствующий объект объект совпадения. Возвращает None если строка не соответствует шаблону; обратите внимание, что это отличается от совпадения нулевой длины.

Новое в версии 3.4.

re.split(pattern, string, maxsplit=0, flags=0)

Разделяет строку по вхождениям шаблона. Если в шаблоне используются группирующие скобки, то текст всех групп в шаблоне также возвращается как часть результирующего списка. Если maxsplit не равно нулю, происходит не более maxsplit разделений, а остаток строки возвращается как последний элемент списка.

>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']

Если в разделителе есть группирующие скобки, и он соответствует началу строки, результат начнётся с пустой строки. То же самое относится и к концу строки:

>>> re.split('(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']

Таким образом, компоненты разделителя всегда находятся на одних и тех же относительных индексах в результирующем списке.

Примечание

split() в настоящее время не разделяет строку по пустому совпадению шаблона. Например:

>>> re.split('x*', 'axbc')
['a', 'bc']

Хотя 'x*' также соответствует 0 'x' перед 'a', между 'b' и 'c' и после 'c', в настоящее время эти совпадения игнорируются. Правильное поведение (т.е. разделение по пустым совпадениям и возврат ['', 'a', 'b', 'c', '']) будет реализовано в будущих версиях Python, но поскольку это изменение несовместимо с предыдущими версиями, в то же время будет поднято предупреждение FutureWarning.

Шаблоны, которые могут соответствовать только пустым строкам, в настоящее время никогда не разделяют строку. Поскольку это не соответствует ожидаемому поведению, начиная с Python 3.5, будет поднято исключение ValueError:

>>> re.split("^$", "foo\n\nbar\n", flags=re.M)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
ValueError: split() requires a non-empty pattern match.

Изменено в версии 3.1: Добавлен необязательный аргумент flags.

Изменено в версии 3.5: Разделение по шаблону, который может соответствовать пустой строке, теперь вызывает предупреждение. Шаблоны, которые могут соответствовать только пустым строкам, теперь отклоняются.

re.findall(pattern, string, flags=0)

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

END_OF_DOCUMENT_MARKER
re.finditer(pattern, string, flags=0)

Возвращает итератор, который возвращает объекты совпадения для всех неперекрывающихся совпадений регулярного выражения pattern в string. Строка сканируется слева направо, а совпадения возвращаются в порядке их нахождения. Пустые совпадения включаются в результат, если они не касаются начала другого совпадения.

re.sub(pattern, repl, string, count=0, flags=0)

Возвращает строку, полученную путём замены левых крайних неперекрывающихся вхождений pattern в string заменой repl. Если шаблон не найден, возвращается string без изменений. repl может быть строкой или функцией; если это строка, все обратные слэши в ней обрабатываются. То есть, \n преобразуется в один символ новой строки, \r преобразуется в символ возврата каретки и так далее. Неизвестные управляющие последовательности, например \& оставляются без изменений. Обратные ссылки, такие как \6, заменяются подстрокой, соответствующей группе 6 в шаблоне. Например:

>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
...        r'static PyObject*\npy_\1(void)\n{',
...        'def myfunc():')
'static PyObject*\npy_myfunc(void)\n{'

Если repl — это функция, она вызывается для каждого неперекрывающегося вхождения pattern. Функция получает в качестве аргумента объект совпадения и возвращает строку замены. Например:

>>> def dashrepl(matchobj):
...     if matchobj.group(0) == '-': return ' '
...     else: return '-'
>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files')
'pro--gram files'
>>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)
'Baked Beans & Spam'

Шаблон может быть строкой или объектом RE.

Необязательный аргумент count — максимальное количество замен вхождений шаблона; count должен быть неотрицательным целым числом. Если он опущен или равен нулю, будут заменены все вхождения. Пустые совпадения шаблона заменяются только в том случае, если они не примыкают к предыдущему совпадению, поэтому sub('x*', '-', 'abc') возвращает '-a-b-c-'.

В аргументах типа repl, помимо описанных выше управляющих последовательностей и обратных ссылок, \g<name> будет использовать подстроку, соответствующую группе с именем name, как определено синтаксисом (?P<name>...) . \g<number> использует соответствующий номер группы; \g<2> поэтому эквивалентен \2, но не двусмысленен в замене, такой как \g<2>0. \20 будет интерпретировано как ссылка на группу 20, а не как ссылка на группу 2, за которой следует буква '0'. Обратная ссылка \g<0> заменяет всю подстроку, соответствующую регулярному выражению.

Изменено в версии 3.1: Добавлен необязательный аргумент flags.

Изменено в версии 3.5: Несовпадающие группы заменяются пустой строкой.

Устарело начиная с версии 3.5, будет удалено в версии 3.6: Неизвестные управляющие последовательности, состоящие из '\' и букв ASCII, теперь вызывают предупреждение об устаревании и будут запрещены в Python 3.6.

re.subn(pattern, repl, string, count=0, flags=0)

Выполняет ту же операцию, что и sub(), но возвращает кортеж (new_string, number_of_subs_made).

Изменено в версии 3.1: Добавлен необязательный аргумент flags.

Изменено в версии 3.5: Несовпадающие группы заменяются пустой строкой.

re.escape(pattern)

Экранирует все символы в pattern, за исключением букв, цифр ASCII и '_'. Это полезно, если вы хотите сопоставить произвольную строку, которая может содержать метасимволы регулярных выражений. Например:

>>> print(re.escape('python.exe'))
python\.exe

>>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
>>> print('[%s]+' % re.escape(legal_chars))
[abcdefghijklmnopqrstuvwxyz0123456789\!\#\$\%\&\'\*\+\-\.\^_\`\|\~\:]+

>>> operators = ['+', '-', '*', '/', '**']
>>> print('|'.join(map(re.escape, sorted(operators, reverse=True))))
\/|\-|\+|\*\*|\*

Изменено в версии 3.3: Символ '_' больше не экранируется.

re.purge()

Очищает кэш регулярных выражений.

exception re.error(msg, pattern=None, pos=None)

Исключение, которое возникает, когда строка, переданная одной из функций, не является допустимым регулярным выражением (например, содержит несовпадающие скобки), или когда во время компиляции или сопоставления возникает какая-либо другая ошибка. Ошибка не возникает, если строка не содержит совпадений для шаблона. Объект исключения имеет следующие дополнительные атрибуты:

msg

Неформализованное сообщение об ошибке.

pattern

Шаблон регулярного выражения.

pos

Индекс в pattern, где произошла ошибка компиляции (может быть None).

lineno

Строка, соответствующая pos (может быть None).

colno

Столбец, соответствующий pos (может быть None).

Изменено в версии 3.5: Добавлены дополнительные атрибуты.

3. Объекты регулярных выражений

Компилированные объекты регулярных выражений поддерживают следующие методы и атрибуты:

regex.search(string[, pos[, endpos]])

Ищет в string первое местоположение, где это регулярное выражение даёт совпадение, и возвращает соответствующий объект совпадения. Возвращает None если в строке нет позиции, соответствующей шаблону; обратите внимание, что это отличается от поиска совпадения нулевой длины в какой-либо точке строки.

Необязательный второй параметр pos задаёт индекс в строке, с которого начинается поиск; по умолчанию он равен 0. Это не полностью эквивалентно срезу строки; метасимвол '^' совпадает с началом строки и позициями сразу после новой строки, но не обязательно с индексом, с которого должен начинаться поиск.

Необязательный параметр endpos ограничивает область поиска в строке; это будет как если бы строка имела длину endpos символов, поэтому будут проверяться только символы от pos до endpos - 1. Если endpos меньше pos, совпадение не будет найдено; в противном случае, если rx — это объект компилированного регулярного выражения, rx.search(string, 0, 50) эквивалентно rx.search(string[:50], 0).

>>> pattern = re.compile("d")
>>> pattern.search("dog")     # Match at index 0
<_sre.SRE_Match object; span=(0, 1), match='d'>
>>> pattern.search("dog", 1)  # No match; search doesn't include the "d"
regex.match(string[, pos[, endpos]])

Если нуль или более символов в начале string совпадают с этим регулярным выражением, возвращает соответствующий объект совпадения. Возвращает None если строка не соответствует шаблону; обратите внимание, что это отличается от совпадения нулевой длины.

Необязательные параметры pos и endpos имеют то же значение, что и для метода search().

>>> pattern = re.compile("o")
>>> pattern.match("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.match("dog", 1)   # Match as "o" is the 2nd character of "dog".
<_sre.SRE_Match object; span=(1, 2), match='o'>

Если вы хотите найти совпадение где угодно в string, используйте search() (см. также search() vs. match()).

regex.fullmatch(string[, pos[, endpos]])

Если вся string соответствует этому регулярному выражению, возвращает соответствующий объект совпадения. Возвращает None если строка не соответствует шаблону; обратите внимание, что это отличается от совпадения нулевой длины.

Необязательные параметры pos и endpos имеют то же значение, что и для метода search().

>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("ogre")     # No match as not the full string matches.
>>> pattern.fullmatch("doggie", 1, 3)   # Matches within given limits.
<_sre.SRE_Match object; span=(1, 3), match='og'>

Введено в версии 3.4.

regex.split(string, maxsplit=0)

Идентично функции split(), использующей скомпилированный шаблон.

regex.findall(string[, pos[, endpos]])

Аналогично функции findall(), использующей скомпилированный шаблон, но также принимает необязательные параметры pos и endpos, которые ограничивают область поиска, как и для match().

regex.finditer(string[, pos[, endpos]])

Аналогично функции finditer(), использующей скомпилированный шаблон, но также принимает необязательные параметры pos и endpos, которые ограничивают область поиска, как и для match().

regex.sub(repl, string, count=0)

Идентично функции sub(), использующей скомпилированный шаблон.

regex.subn(repl, string, count=0)

Идентично функции subn(), использующей скомпилированный шаблон.

regex.flags

Флаги сопоставления регулярных выражений. Это комбинация флагов, переданных в compile(), любых (?...) встроенных флагов в шаблоне и неявных флагов, таких как UNICODE , если шаблон — строка Unicode.

regex.groups

Количество захватывающих групп в шаблоне.

regex.groupindex

Словарь, сопоставляющий имена символических групп, определённые с помощью (?P<id>), с номерами групп. Словарь пустой, если в шаблоне не использовались символические группы.

regex.pattern

Строка шаблона, из которой был скомпилирован объект RE.

4. Объекты совпадения

Объекты совпадения всегда имеют булево значение True. Поскольку match() и search() возвращают None в случае отсутствия совпадения, вы можете проверить, было ли совпадение, с помощью простого оператора if:

match = re.search(pattern, string)
if match:
    process(match)

Объекты совпадения поддерживают следующие методы и атрибуты:

match.expand(template)

Возвращает строку, полученную путём подстановки обратных слэшей в строку шаблона template, как это делает метод sub(). Экранирования, такие как \n, преобразуются в соответствующие символы, а числовые ссылки обратной связи (\1, \2) и именованные ссылки обратной связи (\g<1>, \g<name>) заменяются содержимым соответствующей группы.

Изменено в версии 3.5: Несопоставленные группы заменяются пустой строкой.

match.group([group1, ...])

Возвращает одну или несколько подгрупп совпадения. Если есть один аргумент, результатом является одна строка; если есть несколько аргументов, результатом является кортеж с одним элементом на каждый аргумент. Без аргументов group1 по умолчанию равен нулю (возвращается всё совпадение). Если аргумент groupN равен нулю, соответствующее возвращаемое значение — вся строка совпадения; если он находится в диапазоне от 1 до 99, это строка, соответствующая соответствующей скобчатой группе. Если номер группы отрицательный или больше, чем количество групп, определённых в шаблоне, генерируется исключение IndexError. Если группа содержится в части шаблона, которая не совпала, соответствующее значение результата — None. Если группа содержится в части шаблона, которая совпала несколько раз, возвращается последнее совпадение.

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0)       # The entire match
'Isaac Newton'
>>> m.group(1)       # The first parenthesized subgroup.
'Isaac'
>>> m.group(2)       # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2)    # Multiple arguments give us a tuple.
('Isaac', 'Newton')

Если регулярное выражение использует синтаксис (?P<name>...), аргументы groupN также могут быть строками, идентифицирующими группы по их имени. Если строковый аргумент не используется как имя группы в шаблоне, возникает исключение IndexError.

Довольно сложный пример:

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name')
'Malcolm'
>>> m.group('last_name')
'Reynolds'

Именованные группы также могут ссылаться на их индекс:

>>> m.group(1)
'Malcolm'
>>> m.group(2)
'Reynolds'

Если группа соответствует нескольким раз, доступно только последнее совпадение:

>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.
>>> m.group(1)                        # Returns only the last match.
'c3'
match.groups(default=None)

Возвращает кортеж, содержащий все подгруппы совпадения, начиная с 1 и до количества групп в шаблоне. Аргумент default используется для групп, которые не участвовали в совпадении; по умолчанию он равен None.

Например:

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

Если мы сделаем десятичную точку и всё после неё необязательными, не все группы могут участвовать в совпадении. Эти группы будут по умолчанию None, если не задан аргумент default:

>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups()      # Second group defaults to None.
('24', None)
>>> m.groups('0')   # Now, the second group defaults to '0'.
('24', '0')
match.groupdict(default=None)

Возвращает словарь, содержащий все именованные подгруппы совпадения, с ключами, соответствующими именам подгрупп. Аргумент default используется для групп, которые не участвовали в совпадении; по умолчанию он равен None. Например:

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict()
{'first_name': 'Malcolm', 'last_name': 'Reynolds'}
match.start([group])
match.end([group])

Возвращает индексы начала и конца подстроки, соответствующей group; group по умолчанию равен нулю (означает всю сопоставленную подстроку). Возвращает -1 если group существует, но не участвовала в совпадении. Для объекта совпадения m и группы g, которая участвовала в совпадении, подстрока, соответствующая группе g (эквивалентна m.group(g)) равна

m.string[m.start(g):m.end(g)]

Обратите внимание, что m.start(group) будет равно m.end(group) если group соответствовала пустой строке. Например, после m = re.search('b(c?)', 'cba'), m.start(0) равно 1, m.end(0) равно 2, m.start(1) и m.end(1) оба равны 2, а m.start(2) вызывает исключение IndexError.

Пример, который удалит remove_this из адресов электронной почты:

>>> email = "tony@tiremove_thisger.net"
>>> m = re.search("remove_this", email)
>>> email[:m.start()] + email[m.end():]
'tony@tiger.net'
match.span([group])

Для совпадения m возвращает кортеж (m.start(group), m.end(group)). Обратите внимание, что если group не участвовала в совпадении, это (-1, -1). group по умолчанию равна нулю, всему совпадению.

match.pos

Значение pos, переданное методу search() или match() объекта объекта regex. Это индекс в строке, с которого движок RE начал поиск совпадения.

match.endpos

Значение endpos, переданное методу search() или match() объекта объекта regex. Это индекс в строке, за которым движок RE не будет искать.

match.lastindex

Целочисленный индекс последней сопоставленной группы захвата, или None если ни одна группа не была сопоставлена. Например, выражения (a)b, ((a)(b)), и ((ab)) будут иметь значение lastindex == 1 при применении к строке 'ab', в то время как выражение (a)(b) будет иметь значение lastindex == 2, если применить к той же строке.

match.lastgroup

Имя последней сопоставленной группы захвата, или None если у группы нет имени, или если ни одна группа не была сопоставлена.

match.re

Объект регулярного выражения, метод match() или search() которого произвел этот экземпляр совпадения.

match.string

Строка, переданная методам match() или search().

5. Примеры регулярных выражений

5.1. Проверка на пару

В этом примере мы будем использовать следующую вспомогательную функцию, чтобы отображать объекты совпадения немного более удобочитаемо:

def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

Предположим, вы пишете программу для игры в покер, где рука игрока представлена в виде строки из 5 символов, каждый символ которого представляет карту: «a» для туза, «k» для короля, «q» для дамы, «j» для валета, «t» для 10, а «2» — «9» для карт с этим значением.

Чтобы проверить, является ли данная строка валидной рукой, можно сделать следующее:

>>> valid = re.compile(r"^[a2-9tjqk]{5}$")
>>> displaymatch(valid.match("akt5q"))  # Valid.
"<Match: 'akt5q', groups=()>"
>>> displaymatch(valid.match("akt5e"))  # Invalid.
>>> displaymatch(valid.match("akt"))    # Invalid.
>>> displaymatch(valid.match("727ak"))  # Valid.
"<Match: '727ak', groups=()>"

Последняя рука, "727ak", содержала пару, или две карты с одинаковым значением. Для соответствия этому с помощью регулярного выражения можно использовать обратные ссылки следующим образом:

>>> pair = re.compile(r".*(.).*\1")
>>> displaymatch(pair.match("717ak"))     # Pair of 7s.
"<Match: '717', groups=('7',)>"
>>> displaymatch(pair.match("718ak"))     # No pairs.
>>> displaymatch(pair.match("354aa"))     # Pair of aces.
"<Match: '354aa', groups=('a',)>"

Чтобы узнать, какая карта образует пару, можно использовать метод group() объекта совпадения следующим образом:

>>> pair.match("717ak").group(1)
'7'

# Error because re.match() returns None, which doesn't have a group() method:
>>> pair.match("718ak").group(1)
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    re.match(r".*(.).*\1", "718ak").group(1)
AttributeError: 'NoneType' object has no attribute 'group'

>>> pair.match("354aa").group(1)
'a'

5.2. Моделирование scanf()

В настоящее время Python не имеет эквивалента scanf(). Регулярные выражения обычно более мощные, хотя и более громоздкие, чем строки форматирования scanf(). Таблица ниже предлагает более или менее эквивалентные соответствия между разделителями форматирования scanf() и регулярными выражениями.

scanf() Разделитель Регулярное выражение
%c .
%5c .{5}
%d [-+]?\d+
%e, %E, %f, %g [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
%i [-+]?(0[xX][\dA-Fa-f]+|0[0-7]*|\d+)
%o [-+]?[0-7]+
%s \S+
%u \d+
%x, %X [-+]?(0[xX])?[\dA-Fa-f]+

Чтобы извлечь имя файла и числа из строки вроде

/usr/sbin/sendmail - 0 errors, 4 warnings

вы бы использовали форматирование scanf()

%s - %d errors, %d warnings

Эквивалентное регулярное выражение было бы

(\S+) - (\d+) errors, (\d+) warnings

5.3. search() vs. match()

Python предлагает две различные базовые операции, основанные на регулярных выражениях: re.match() проверяет совпадение только в начале строки, в то время как re.search() проверяет совпадение в любой части строки (это то, что Perl делает по умолчанию).

Например:

>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<_sre.SRE_Match object; span=(2, 3), match='c'>

Регулярные выражения, начинающиеся с '^', можно использовать с search(), чтобы ограничить соответствие началом строки:

>>> re.match("c", "abcdef")    # No match
>>> re.search("^c", "abcdef")  # No match
>>> re.search("^a", "abcdef")  # Match
<_sre.SRE_Match object; span=(0, 1), match='a'>

Однако обратите внимание, что в режиме MULTILINE match() соответствует только началу строки, тогда как использование search() с регулярным выражением, начинающимся с '^', будет соответствовать началу каждой строки.

>>> re.match('X', 'A\nB\nX', re.MULTILINE)  # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE)  # Match
<_sre.SRE_Match object; span=(4, 5), match='X'>

5.4. Создание телефонной книги

split() разбивает строку на список, ограниченный переданным шаблоном. Этот метод незаменим для преобразования текстовых данных в структуры данных, которые легко читаются и изменяются в Python, как показано в следующем примере создания телефонной книги.

Сначала вот входные данные. Обычно они могут поступать из файла, здесь мы используем синтаксис строк с тройными кавычками:

>>> text = """Ross McFluff: 834.345.1254 155 Elm Street
...
... Ronald Heathmore: 892.345.3428 436 Finley Avenue
... Frank Burger: 925.541.7625 662 South Dogwood Way
...
...
... Heather Albrecht: 548.326.4584 919 Park Place"""

Записи разделены одной или несколькими строками новой строки. Теперь мы преобразуем строку в список, где каждая непустая строка имеет свою запись:

>>> entries = re.split("\n+", text)
>>> entries
['Ross McFluff: 834.345.1254 155 Elm Street',
'Ronald Heathmore: 892.345.3428 436 Finley Avenue',
'Frank Burger: 925.541.7625 662 South Dogwood Way',
'Heather Albrecht: 548.326.4584 919 Park Place']

Наконец, разделим каждую запись на список с именем, фамилией, номером телефона и адресом. Мы используем параметр maxsplit метода split(), потому что в адресе есть пробелы, которые находятся в нашем разделителе:

>>> [re.split(":? ", entry, 3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919 Park Place']]

Шаблон :? соответствует двоеточию после фамилии, чтобы он не появлялся в результатах. С шаблоном maxsplit 4, мы могли бы разделить номер дома от названия улицы:

>>> [re.split(":? ", entry, 4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919', 'Park Place']]

5.5. Обработка текста

sub() заменяет каждое вхождение шаблона строкой или результатом функции. Этот пример демонстрирует использование sub() с функцией для «обработки» текста или случайной перестановки порядка всех символов в каждом слове предложения, кроме первых и последних символов:

>>> def repl(m):
...     inner_word = list(m.group(2))
...     random.shuffle(inner_word)
...     return m.group(1) + "".join(inner_word) + m.group(3)
>>> text = "Professor Abdolmalek, please report your absences promptly."
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Poefsrosr Aealmlobdk, pslaee reorpt your abnseces plmrptoy.'
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Pofsroser Aodlambelk, plasee reoprt yuor asnebces potlmrpy.'

5.6. Поиск всех наречий

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

>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']

5.7. Поиск всех наречий и их позиций

Если нужно больше информации обо всех соответствиях шаблона, чем соответствующий текст, finditer() будет полезен, так как он предоставляет объекты соответствия вместо строк. Продолжая предыдущий пример, если человек был писателем, который хотел найти все наречия и их позиции в каком-то тексте, он мог бы использовать finditer() следующим образом:

>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly", text):
...     print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
07-16: carefully
40-47: quickly

5.8. Нотация строк-сырья

Нотация строк-сырья (r"text") поддерживает регулярные выражения в приличном состоянии. Без нее каждый обратный слеш ('\') в регулярном выражении нужно было бы предварять ещё одним, чтобы экранировать его. Например, две следующие строки кода функционально идентичны:

>>> re.match(r"\W(.)\1\W", " ff ")
<_sre.SRE_Match object; span=(0, 4), match=' ff '>
>>> re.match("\\W(.)\\1\\W", " ff ")
<_sre.SRE_Match object; span=(0, 4), match=' ff '>

Когда нужно сопоставить обратный слеш в прямом виде, его необходимо экранировать в регулярном выражении. С нотацией строк-сырья это означает r"\\". Без нотации строк-сырья нужно использовать "\\\\", что делает следующие строки кода функционально идентичными:

>>> re.match(r"\\", r"\\")
<_sre.SRE_Match object; span=(0, 1), match='\\'>
>>> re.match("\\\\", r"\\")
<_sre.SRE_Match object; span=(0, 1), match='\\'>

5.9. Создание токенизатора

Токенизатор или сканер анализирует строку для категоризации групп символов. Это полезный первый шаг при написании компилятора или интерпретатора.

Категории текста задаются регулярными выражениями. Приём заключается в объединении этих выражений в одно общее регулярное выражение и проходе по последовательным соответствиям:

import collections
import re

Token = collections.namedtuple('Token', ['typ', 'value', 'line', 'column'])

def tokenize(code):
    keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
    token_specification = [
        ('NUMBER',  r'\d+(\.\d*)?'),  # Integer or decimal number
        ('ASSIGN',  r':='),           # Assignment operator
        ('END',     r';'),            # Statement terminator
        ('ID',      r'[A-Za-z]+'),    # Identifiers
        ('OP',      r'[+\-*/]'),      # Arithmetic operators
        ('NEWLINE', r'\n'),           # Line endings
        ('SKIP',    r'[ \t]+'),       # Skip over spaces and tabs
        ('MISMATCH',r'.'),            # Any other character
    ]
    tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
    line_num = 1
    line_start = 0
    for mo in re.finditer(tok_regex, code):
        kind = mo.lastgroup
        value = mo.group(kind)
        if kind == 'NEWLINE':
            line_start = mo.end()
            line_num += 1
        elif kind == 'SKIP':
            pass
        elif kind == 'MISMATCH':
            raise RuntimeError('%r unexpected on line %d' % (value, line_num))
        else:
            if kind == 'ID' and value in keywords:
                kind = value
            column = mo.start() - line_start
            yield Token(kind, value, line_num, column)

statements = '''
    IF quantity THEN
        total := total + price * quantity;
        tax := price * 0.05;
    ENDIF;
'''

for token in tokenize(statements):
    print(token)

Токенизатор производит следующий вывод:

Token(typ='IF', value='IF', line=2, column=4)
Token(typ='ID', value='quantity', line=2, column=7)
Token(typ='THEN', value='THEN', line=2, column=16)
Token(typ='ID', value='total', line=3, column=8)
Token(typ='ASSIGN', value=':=', line=3, column=14)
Token(typ='ID', value='total', line=3, column=17)
Token(typ='OP', value='+', line=3, column=23)
Token(typ='ID', value='price', line=3, column=25)
Token(typ='OP', value='*', line=3, column=31)
Token(typ='ID', value='quantity', line=3, column=33)
Token(typ='END', value=';', line=3, column=41)
Token(typ='ID', value='tax', line=4, column=8)
Token(typ='ASSIGN', value=':=', line=4, column=12)
Token(typ='ID', value='price', line=4, column=15)
Token(typ='OP', value='*', line=4, column=21)
Token(typ='NUMBER', value='0.05', line=4, column=23)
Token(typ='END', value=';', line=4, column=27)
Token(typ='ENDIF', value='ENDIF', line=5, column=4)
Token(typ='END', value=';', line=5, column=9)

© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/re.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API