Spec-Zone.ru › Python 3.8

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

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

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

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

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

Решение заключается в использовании синтаксиса необработанных строк Python для шаблонов регулярных выражений; обратные слэши не обрабатываются каким-либо специальным образом в строковом литерале, префикс которого '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)

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

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

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

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

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

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

Возвращает строку, полученную путем замены левых неперекрывающихся вхождений pattern в string заменой repl. Если шаблон не найден, string возвращается без изменений. 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 является функцией, она вызывается для каждого неперекрывающегося вхождения 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'

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

Необязательный аргумент 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: Неизвестные экранирования в pattern, состоящие из '\' и 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)

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

>>> print(re.escape('http://www.python.org'))
http://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

Индекс в pattern, где произошла ошибка компиляции (может быть 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]])

Если ноль или более символов в начале строки совпадают с этим регулярным выражением, возвращает соответствующий объект совпадения. Возвращает 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'>

Если вы хотите найти совпадение в любом месте строки, используйте 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 возвращает кортеж из 2 элементов (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» для 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 = 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", text)
['carefully', 'quickly']

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

Если кому-то нужна дополнительная информация обо всех совпадениях шаблона, кроме совпадающего текста, 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

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

Нотация строк-сырья (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='\\'>

Создание разделителя

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

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

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.8/library/re.html

Spec-Zone.ru

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