Spec-Zone.ru › Python 3.10

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 также использует обратную косую черту в качестве escape-последовательности в строковых литералах; если escape-последовательность не распознаётся парсером 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 вызывается, если множество символов содержит конструкции, которые изменят семантику в будущем.

END_OF_DOCUMENT_MARKER
|

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 (по умолчанию). Это переопределение действует только для узкой вложенной группы, а исходный режим сопоставления восстанавливается за пределами группы.

New in version 3.6.

Changed in version 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. Внутри '[' и ']' класса символов все числовые escape-последовательности обрабатываются как символы.

\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; это включает алфавитно-цифровые символы (определяемые str.isalnum()), а также символ подчеркивания (_). Если используется флаг ASCII, соответствует только [a-zA-Z0-9_].

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

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

\W

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

\Z

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

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

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

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

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

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

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

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

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

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

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

Флаги

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

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.compile(pattern, flags=0)

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

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

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

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

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

result = re.match(pattern, string)

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

Примечание

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

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

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

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

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

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

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

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

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

New in version 3.4.

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

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

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

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

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

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

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

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

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

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

Возвращает строку, полученную путём замены левых неперекрывающихся вхождений pattern в string на repl. Если шаблон не найден, string возвращается без изменений. repl может быть строкой или функцией; если это строка, любые обратные слэши в ней обрабатываются. То есть, \n преобразуется в один символ новой строки, \r преобразуется в символ возврата каретки и так далее. Неизвестные escapes ASCII букв зарезервированы для будущего использования и обрабатываются как ошибки. Другие неизвестные escapes, такие как \& остаются без изменений. Обратные ссылки, такие как \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, помимо описанных выше символьных escapes и обратных ссылок, \g<name> будет использовать подстроку, соответствующую группе с именем name, как определено синтаксисом (?P<name>...). \g<number> использует соответствующий номер группы; \g<2> поэтому эквивалентно \2, но не неоднозначно в замене, такой как \g<2>0. \20 будет интерпретироваться как ссылка на группу 20, а не как ссылка на группу 2 и букву '0'. Обратная ссылка \g<0> подставляет всю подстроку, соответствующую регулярному выражению.

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

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

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

Изменено в версии 3.7: Неизвестные escapes в 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('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

Индекс в 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]])

Если нуль или более символов в начале 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]])

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

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

>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("ogre")     # No match as not the full string matches.
>>> pattern.fullmatch("doggie", 1, 3)   # Matches within given limits.
<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 , если шаблон — строка Юникода.

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)

Возвращает строку, полученную путём подстановки обратных слэшей в шаблонную строку шаблон, как это делает метод 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])

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

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

Обратите внимание, что m.start(group) будет равно m.end(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)). Обратите внимание, что если группа не внесла вклад в совпадение, это (-1, -1). Группа по умолчанию равна нулю, всё совпадение.

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.fullmatch() проверяет, является ли вся строка совпадением

Например:

>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<re.Match object; span=(2, 3), match='c'>
>>> re.fullmatch("p.*n", "python") # Match
<re.Match object; span=(0, 6), match='python'>
>>> re.fullmatch("r.*n", "python") # No match

Регулярные выражения, начинающиеся с '^', могут использоваться с 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/re.html

Spec-Zone.ru

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