Spec-Zone.ru › Python 3.9

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

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

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

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

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

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

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

См. также

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

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

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

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

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

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

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

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

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

.

(Точка.) В режиме по умолчанию соответствует любому символу, кроме новой строки. Если флаг DOTALL был указан, он соответствует любому символу, включая новую строку.

^

(Знак каретки.) Соответствует началу строки, и в режиме MULTILINE также соответствует сразу после каждой новой строки.

$

Соответствует концу строки или сразу перед новой строкой в конце строки, и в режиме MULTILINE также соответствует перед новой строкой. foo соответствует как «foo», так и «foobar», в то время как регулярное выражение foo$ соответствует только «foo». Более интересно, поиск foo.$ в 'foo1\nfoo2\n' соответствует «foo2» обычно, но «foo1» в режиме MULTILINE; поиск одиночного $ в 'foo\n' найдёт два (пустых) соответствия: одно сразу перед новой строкой и одно в конце строки.

*

Приводит к тому, что полученное RE соответствует 0 или более повторениям предыдущего RE, как можно больше повторений. ab* будет соответствовать «a», «ab» или «a», за которым следует любое количество «b».

+

Приводит к тому, что полученное RE соответствует 1 или более повторениям предыдущего RE. ab+ будет соответствовать «a», за которым следует любое ненулевое количество «b»; оно не будет соответствовать только «a».

?

Приводит к тому, что полученное RE соответствует 0 или 1 повторениям предыдущего RE. ab? будет соответствовать либо «a», либо «ab».

*?, +?, ??

Квалификаторы '*', '+', и '?' являются жадными; они соответствуют как можно большему количеству текста. Иногда такое поведение нежелательно; если RE <.*> сопоставляется со строкой '<a> b <c>', он будет соответствовать всей строке, а не только '<a>'. Добавление ? после квалификатора заставляет его выполнять сопоставление в нежадном или минимальном режиме; будет сопоставлено как можно меньше символов. Использование RE <.*?> будет соответствовать только '<a>'.

{m}

Указывает, что должно быть сопоставлено ровно m копий предыдущего RE; меньшее количество сопоставлений приводит к тому, что всё RE не соответствует. Например, a{6} будет соответствовать ровно шести 'a' символам, но не пяти.

{m,n}

Приводит к тому, что полученное RE соответствует от m до n повторений предыдущего RE, пытаясь сопоставить как можно больше повторений. Например, a{3,5} будет соответствовать от 3 до 5 'a' символов. Опущение m задаёт нижнюю границу 0, а опущение n задаёт бесконечную верхнюю границу. Например, a{4,}b будет соответствовать 'aaaab' или тысяче 'a' символов, за которыми следует 'b', но не 'aaab'. Запятая не может быть опущена, иначе модификатор был бы слит с ранее описанной формой.

{m,n}?

Приводит к тому, что полученное RE соответствует от m до n повторений предыдущего RE, пытаясь сопоставить как можно меньше повторений. Это нежадная версия предыдущего квалификатора. Например, в строке из 6 символов 'aaaaaa', a{3,5} будет соответствовать 5 'a' символов, в то время как a{3,5}? будет соответствовать только 3 символам.

\

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

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

[]

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

  • Символы могут быть перечислены индивидуально, например, [amk] будет соответствовать 'a', 'm', или 'k'.
  • Диапазоны символов могут быть указаны, задав два символа и разделив их дефисом, например, [a-z] соответствует любой строчной букве ASCII, [0-5][0-9] соответствует всем двузначным числам от 00 до 59, и [0-9A-Fa-f] соответствует любой шестнадцатеричной цифре. Если дефис экранирован (например, [a\-z]) или если он расположен первым или последним символом (например, [-a] или [a-]), он будет соответствовать буквальному дефису.
  • Специальные символы теряют своё специальное значение внутри наборов. Например, [(+*)] будет соответствовать любому из буквальных символов '(', '+', '*', или ')'.
  • Классы символов, такие как \w или \S (определены ниже), также принимаются внутри набора, хотя символы, которым они соответствуют, зависят от того, установлен ли режим ASCII или LOCALE.
  • Символам, которые не входят в диапазон, можно соответствовать путём дополнения набора. Если первый символ набора является '^', все символы, которые не входят в набор, будут сопоставлены. Например, [^5] будет соответствовать любому символу, кроме '5', и [^^] будет соответствовать любому символу, кроме '^'. ^ не имеет специального значения, если это не первый символ в наборе.
  • Для сопоставления буквального ']' внутри набора необходимо предварять его обратной косой чертой или помещать его в начало набора. Например, и [()[\]{}] и []()[{}] будут соответствовать скобке.
  • Поддержка вложенных наборов и операций над наборами, как в Unicode Technical Standard #18, может быть добавлена в будущем. Это изменит синтаксис, поэтому для облегчения этой смены, в неоднозначных случаях будет генерироваться FutureWarning. Это включает наборы, начинающиеся с буквального '[' или содержащие буквальные последовательности символов '--', '&&', '~~', и '||'. Чтобы избежать предупреждения, экранируйте их обратной косой чертой.

Изменено в версии 3.7: FutureWarning генерируется, если набор символов содержит конструкции, семантика которых изменится в будущем.

|

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.U (сопоставление с Unicode) и re.X (подробный), для всего регулярного выражения. (Флаги описаны в Содержимое модуля.) Это полезно, если вы хотите включить флаги в состав регулярного выражения вместо передачи аргумента flag функции re.compile(). Флаги должны использоваться первыми в строке выражения.

(?:...)

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

(?aiLmsux-imsx:...)

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

Буквы 'a', 'L' и 'u' взаимно исключают друг друга при использовании в качестве флагов внутри группы, поэтому их нельзя объединять или следовать за '-'. Вместо этого, когда один из них появляется в строке внутри группы, он переопределяет режим сопоставления в содержащей группе. В шаблонах Unicode (?a:...) переключается на сопоставление только с ASCII, а (?u:...) — на сопоставление с Unicode (по умолчанию). В шаблонах байтов (?L:...) переключается на сопоставление, зависящее от локали, а (?a:...) переключается на сопоставление только с ASCII (по умолчанию). Это переопределение действует только для узкой вложенной группы, а исходный режим сопоставления восстанавливается за пределами группы.

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

Изменено в версии 3.7: Буквы 'a', 'L' и 'u' также могут быть использованы в группе.

(?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', так как обратный поиск вернётся на 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(r'(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

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

(?<!...)

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

(?(id/name)yes-pattern|no-pattern)

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

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

\number

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

\A

Совпадает только в начале строки.

\b

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

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

\B

Совпадает с пустой строкой, но только тогда, когда она не находится в начале или конце слова. Это означает, что r'py\B' соответствует 'python', 'py3', 'py2', но не 'py', 'py.', или 'py!'. \B — это просто противоположность \b, поэтому символы слов в шаблонах Unicode — это алфавитно-цифровые символы Unicode или нижнее подчеркивание, хотя это можно изменить, используя флаг ASCII. Границы слов определяются текущим языковым стандартом, если используется флаг LOCALE.

\d
Для шаблонов Unicode (str):

Совпадает с любой десятичной цифрой Unicode (то есть любым символом в категории Unicode [Nd]). Это включает [0-9], а также многие другие символы цифр. Если используется флаг ASCII, совпадает только [0-9].

Для шаблонов 8-битных (bytes):

Совпадает с любой десятичной цифрой; это эквивалентно [0-9].

\D

Совпадает с любым символом, который не является десятичной цифрой. Это противоположно \d. Если используется флаг ASCII, это становится эквивалентно [^0-9].

\s
Для шаблонов Unicode (str):

Совпадает с символами пробелов Unicode (включая [ \t\n\r\f\v], и также многие другие символы, например, неразрывные пробелы, предписанные правилами типографики во многих языках). Если используется флаг ASCII, совпадает только [ \t\n\r\f\v].

Для шаблонов 8-битных (bytes):

Совпадает с символами, рассматриваемыми как пробелы в наборе символов ASCII; это эквивалентно [ \t\n\r\f\v].

\S

Совпадает с любым символом, который не является символом пробела. Это противоположно \s. Если используется флаг ASCII, это становится эквивалентно [^ \t\n\r\f\v].

\w
Для шаблонов Unicode (str):

Совпадает с символами слов Unicode; это включает большинство символов, которые могут быть частью слова на любом языке, а также цифры и знак подчеркивания. Если используется флаг ASCII, совпадает только [a-zA-Z0-9_].

Для шаблонов 8-битных (bytes):

Совпадает с символами, рассматриваемыми как буквенно-цифровые в наборе символов ASCII; это эквивалентно [a-zA-Z0-9_]. Если используется флаг LOCALE, совпадают символы, рассматриваемые как буквенно-цифровые в текущем языковом стандарте, и знак подчеркивания.

\W

Совпадает с любым символом, который не является символом слова. Это противоположно \w. Если используется флаг ASCII, это становится эквивалентно [^a-zA-Z0-9_]. Если используется флаг LOCALE, совпадают символы, которые не являются алфавитно-цифровыми в текущем языковом стандарте или знаком подчеркивания.

\Z

Совпадает только в конце строки.

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

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

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

'\u', '\U', и '\N' последовательности эскейпов распознаются только в шаблонах Unicode. В шаблонах байтов они являются ошибками. Неизвестные эскейпы ASCII-букв зарезервированы для будущего использования и обрабатываются как ошибки.

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

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

Изменено в версии 3.6: Неизвестные эскейпы, состоящие из '\' и ASCII-буквы, теперь являются ошибками.

Изменено в версии 3.8: Добавлена последовательность эскейпов '\N{name}'. Как и в литералах строк, она расширяется до указанного символа Unicode (например, '\N{EM DASH}').

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

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

Изменено в версии 3.6: Константы флагов теперь являются экземплярами RegexFlag, которые являются подклассом enum.IntFlag.

re.compile(pattern, flags=0)

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

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

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

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 и игнорируется для шаблонов байтов. Соответствует встроенному флагу (?a).

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

re.DEBUG

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

re.I
re.IGNORECASE

Выполнять сопоставление без учёта регистра; выражения, такие как [A-Z] , также будут соответствовать строчным буквам. Полное сопоставление Unicode (например, Ü соответствует ü ) также работает, если не используется флаг re.ASCII для отключения сопоставлений с символами вне ASCII. Текущий локалитет не изменяет эффект этого флага, если также не используется флаг re.LOCALE. Соответствует встроенному флагу (?i).

Обратите внимание, что при использовании Unicode-шаблонов [a-z] или [A-Z] в сочетании с флагом IGNORECASE они будут соответствовать 52 ASCII буквам и 4 дополнительным символам, не являющимся ASCII: ‘İ’ (U+0130, прописная буква I с точкой сверху), ‘ı’ (U+0131, строчная буква i без точки), ‘ſ’ (U+017F, строчная буква долгое s) и ‘K’ (U+212A, знак Кельвина). Если используется флаг ASCII, будут сопоставляться только буквы от ‘a’ до ‘z’ и от ‘A’ до ‘Z’.

re.L
re.LOCALE

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

Изменено в версии 3.6: re.LOCALE может быть использован только с шаблонами байтов и несовместим с re.ASCII.

Изменено в версии 3.7: Скомпилированные объекты регулярных выражений с флагом re.LOCALE больше не зависят от локали во время компиляции. На результат сопоставления влияет только локалитет во время сопоставления.

re.M
re.MULTILINE

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

re.S
re.DOTALL

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

re.X
re.VERBOSE

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

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

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

Соответствует встроенному флагу (?x).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

>>> re.split(r'\b', 'Words, words, words.')
['', 'Words', ', ', 'words', ', ', 'words', '.']
>>> re.split(r'\W*', '...words...')
['', '', 'w', 'o', 'r', 'd', 's', '', '']
>>> re.split(r'(\W*)', '...words...')
['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']

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

Изменено в версии 3.7: Добавлена поддержка разделения на шаблон, который может соответствовать пустой строке.

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

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

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

>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
[('width', '20'), ('height', '10')]

Изменено в версии 3.7: Теперь непустые совпадения могут начинаться сразу после предыдущего пустого совпадения.

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

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

Изменено в версии 3.7: Теперь непустые совпадения могут начинаться сразу после предыдущего пустого совпадения.

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

Возвращает строку, полученную путем замены левого по порядку неперекрывающегося вхождения шаблона в строке заменой repl. Если шаблон не найден, строка возвращается без изменений. repl может быть строкой или функцией; если это строка, все экранированные обратные косые черты в ней обрабатываются. То есть \n преобразуется в один символ новой строки, \r преобразуется в возврат каретки и так далее. Неизвестные экранирования ASCII-букв зарезервированы для будущего использования и обрабатываются как ошибки. Другие неизвестные экранирования, такие как \& , остаются без изменений. Обратные ссылки, такие как \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 является функцией, она вызывается для каждого неперекрывающегося вхождения шаблона. Функция принимает один аргумент — объект совпадения и возвращает строку замены. Например:

>>> 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'

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

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

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

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

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

Изменено в версии 3.6: Неизвестные экранирования в шаблоне, состоящие из '\' и ASCII-буквы, теперь являются ошибками.

Изменено в версии 3.7: Неизвестные экранирования в repl, состоящие из '\' и ASCII-буквы, теперь являются ошибками.

Изменено в версии 3.7: Пустые совпадения шаблона заменяются, если они примыкают к предыдущему непустому совпадению.

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

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

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

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

re.escape(pattern)

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

>>> print(re.escape('https://www.python.org'))
https://www\.python\.org

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

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

Эта функция не должна использоваться для строки замены в sub() и subn(), должны экранироваться только обратные косые черты. Например:

>>> digits_re = r'\d+'
>>> sample = '/usr/sbin/sendmail - 0 errors, 12 warnings'
>>> print(re.sub(digits_re, digits_re.replace('\\', r'\\'), sample))
/usr/sbin/sendmail - \d+ errors, \d+ warnings

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

Изменено в версии 3.7: Экранируются только символы, которые могут иметь специальное значение в регулярном выражении. В результате '!', '"', '%', "'", ',', '/', ':', ';', '<', '=', '>', '@', и "`" больше не экранируются.

re.purge()

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

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

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

msg

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

pattern

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

pos

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

lineno

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

colno

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

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

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

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

Pattern.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
<re.Match object; span=(0, 1), match='d'>
>>> pattern.search("dog", 1)  # No match; search doesn't include the "d"
Pattern.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".
<re.Match object; span=(1, 2), match='o'>

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

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

Если вся строка соответствует этому регулярному выражению, возвращает соответствующий объект соответствия. Возвращает 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.
<re.Match object; span=(1, 3), match='og'>

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

Pattern.split(string, maxsplit=0)

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

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

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

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

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

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

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

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

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

Pattern.flags

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

Pattern.groups

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

Pattern.groupindex

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

Pattern.pattern

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

Изменено в версии 3.7: Добавлена поддержка copy.copy() и copy.deepcopy(). Скомпилированные объекты регулярных выражений считаются атомарными.

Объекты совпадений

Объекты совпадений всегда имеют булево значение 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.__getitem__(g)

Это идентично m.group(g). Это позволяет проще получить доступ к отдельной группе из совпадения:

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m[0]       # The entire match
'Isaac Newton'
>>> m[1]       # The first parenthesized subgroup.
'Isaac'
>>> m[2]       # The second parenthesized subgroup.
'Newton'

Добавлена в версии 3.6.

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() объекта объекта регулярного выражения. Это индекс в строке, с которого движок RE начал поиск совпадения.

Match.endpos

Значение endpos, переданное методу search() или match() объекта объекта регулярного выражения. Это индекс в строке, за которым движок 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().

Изменено в версии 3.7: Добавлена поддержка copy.copy() и copy.deepcopy(). Объекты совпадений считаются атомарными.

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

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

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

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

Предположим, вы пишете программу для игры в покер, где рука игрока представлена строкой из 5 символов, каждый из которых представляет карту: «a» для туза, «k» для короля, «q» для дамы, «j» для валета, «t» для десятки, а «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 = re.compile(r".*(.).*\1")
>>> 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'

Моделирование 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

search() против match()

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

Например:

>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<re.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
<re.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
<re.Match object; span=(4, 5), match='X'>

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

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']]

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

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.'

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

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

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

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

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

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

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

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

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

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

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

Написание токенизатора

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

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

from typing import NamedTuple
import re

class Token(NamedTuple):
    type: str
    value: str
    line: int
    column: int

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()
        column = mo.start() - line_start
        if kind == 'NUMBER':
            value = float(value) if '.' in value else int(value)
        elif kind == 'ID' and value in keywords:
            kind = value
        elif kind == 'NEWLINE':
            line_start = mo.end()
            line_num += 1
            continue
        elif kind == 'SKIP':
            continue
        elif kind == 'MISMATCH':
            raise RuntimeError(f'{value!r} unexpected on line {line_num}')
        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(type='IF', value='IF', line=2, column=4)
Token(type='ID', value='quantity', line=2, column=7)
Token(type='THEN', value='THEN', line=2, column=16)
Token(type='ID', value='total', line=3, column=8)
Token(type='ASSIGN', value=':=', line=3, column=14)
Token(type='ID', value='total', line=3, column=17)
Token(type='OP', value='+', line=3, column=23)
Token(type='ID', value='price', line=3, column=25)
Token(type='OP', value='*', line=3, column=31)
Token(type='ID', value='quantity', line=3, column=33)
Token(type='END', value=';', line=3, column=41)
Token(type='ID', value='tax', line=4, column=8)
Token(type='ASSIGN', value=':=', line=4, column=12)
Token(type='ID', value='price', line=4, column=15)
Token(type='OP', value='*', line=4, column=21)
Token(type='NUMBER', value=0.05, line=4, column=23)
Token(type='END', value=';', line=4, column=27)
Token(type='ENDIF', value='ENDIF', line=5, column=4)
Token(type='END', value=';', line=5, column=9)
Frie09

Фридл, Джеффри. Овладение регулярными выражениями. 3-е изд., O’Reilly Media, 2009. Третье издание книги больше не охватывает Python, но первое издание подробно рассматривало создание эффективных шаблонов регулярных выражений.

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

Spec-Zone.ru

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