Перейти к содержимому

Регулярное выражение python как исключить символы

  • автор:

Убираем конкретные символы из строки

С поомщью str.replace мы можем менять какие-то символы на другие. Если мы просто хотим убрать какие-то символы, тогда просто заменяем их на пустую строку. str.replace() будет применять замену ко всем найденным совподениям.

s="Hello$ Python3$" s1=s.replace("$", "") print (s1) # Результат: Hello Python3

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

s="Hello$ Python3$" s1=s.replace("$", "", 1) print (s1) # Результат: Hello Python3$

С помощью ' re.sub '

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

Возвращает строку, полученную путем замены крайних левых неперекрывающихся
совпадений с шаблоном в строке на значение repl. Если совпадения с шаблоном
не найдены, возвращается неизмененная строка
— Из документации Python'а

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

s="Hello$@& Python3$" import re s1=re.sub("[$|@|&]","",s) print (s1) # Результат: Hello Python3
  • Заменяемый шаблон → “[ $ | @ | & ]”
  • [ ] используется для определения множества
  • $ | @ | & → будет искать $ или @ или &
  • Заменяем на пустую строку
  • Если вышеуказанные символы заменяются найдены, то они заменяются на пустую строку

Убрать все символы, кроме букв

С помощью 'isalpha()'

isalpha() используется для того, чтобы проверять, состоит ли строка только из букв. Возвращает True если является буквой. Мы будем проходить по каждому символу строки и проверять является ли он буквой.

Пример

s="Hello$@ Python3&" s1="".join(c for c in s if c.isalpha()) print (s1) # Результат: HelloPython

(c for c in s if c.isalpha())

Перед нами объект генератор, содержащий все буквы из строки:
s1=””.join(c for c in s if c.isalpha())

””.join будет соединять все символы в одну строку.

С помощью 'filter()'

s = "Hello$@ Python3&" f = filter(str.isalpha, s) s1 = "".join(f) print(s1)

f = filter(str.isalpha, s)

Функция filter() будет применять str.isalpha метод для каждого элемента строки, и если получаем истину , то мы возвращаем элемент. В противном случае - пропускаем.

Функция filter() вернет итератор, содержащий все буквы переданной строки, а join() будем "склеиват" все элементы друг с другом.

С помощью 're.sub()'

s = "Hello$@ Python3$" import re s1 = re.sub("[^A-Za-z]", "", s) print (s1) # Результат: HelloPython

Рассмотрим s1 = re.sub(“[^A-Za-z]”, ””, s)

  • “[ A-Za-z]”* → Ищет все символы, кроме букв. Если в начале множества указать * , тогда к шаблону будут подходить все те символы, которые НЕ указаны в множестве. (для русских слов используйте [^А-Яа-я] - прим. ред.)
  • Все символы, удовлетворяющие шаблону будут заменены на пустую строку.
  • Все символы, кроме букв, будут убраны.

Убрать все символы, кроме букв и чисел

С помощью 'isalnum()'

isalnum() используется, когда мы хотим определить состоит строка только из чисел или букв.

Пройдемся по каждому символу строки, что-бы выявить нужные символы.

s = "Hello$@ Python3&" s1 = "".join(c for c in s if c.isalnum()) print(s1) # Результат: HelloPython3

С помощью 're.sub()'

s = "Hello$@ Python3&_" import re s1 = re.sub("[^A-Za-z0-9]", "", s) print(s1) # Результат: HelloPython3
  • “[^A-Za-z0–9]” → Этот шаблон будет искать все символы, кроме букв и цифр.
  • Все найденные символы будут заменены на пустую строку
  • Все символы, кроме букв и цифры убраны.

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

С помощью 're.sub()'

s = "Hello347 Python3$" import re s1 = re.sub("[0-9]", "", s) print(s1) # Результат: Hello Python$
  • [0-9] - цифры от 0 до 9
  • re.sub(“[0–9]”, ””, s) - если есть совпадения, заменяем на пустую строку

Убираем все символы из строки кроме цифр

С помощью 'isdecimal()'

isdecimal() возвращает истину, если все символы строки являются цифрами, в противном случае возвращается ложь.

s = "1-2$3%4 5a" s1 = "".join(c for c in s if c.isdecimal()) print(s1) # Результат: 12345

Пороходим по каждому символу строки и проверяем и является ли он цифрой. "".join() соединяет все элементы.

С помощью 're.sub()'

s = "1-2$3%4 5a" import re s1 = re.sub("[^0-9]", "", s) print(s1) # Результат: 12345

Рассмотрим s1 = re.sub(“[^0–9]”, ””, s)

  • [^0-9] будет искать все символы кроме от 0 до 9
  • re.sub(“[^0–9]”, ””, s) все символы кроме цифр будут заменены на пустую строку.

С помощью 'filter()'

s = "1-2$3%4 5a" f = filter(str.isdecimal, s) s1 = "".join(f) print(s1) # Результат: 12345

Рассмотрим f = filter(str.isdecimal, s)

Функция filter() будет выполнять str.isdecimal метод для каждого символа, если он возвращает истину, то добовляет его в генератор. Затем генератор распаковывается в готовую строку с помощью метода join() .

Примечание

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

Рекомендуем хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB

Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

По статье задано0 вопрос(ов)

Подписка на обсуждение 4
Подписка на раздел 73

Вам это нравится? Поделитесь в социальных сетях!

HOWTO по регулярным выражениям¶

Документ является вводным руководством по использованию регулярных выражений в Python с использованием модуля re . Он представляет собой более лёгкое знакомство, чем соответствующий раздел в справочнике по библиотеке.

Вступление¶

Регулярные выражения (называемые RE, или регулярными выражениями, или шаблонами регулярных выражений) — это, по сути, крошечный узкоспециализированный язык программирования, встроенный в Python и доступный через модуль re . Используя этот небольшой язык, вы указываете правила для набора возможных строк, которым вы хотите сопоставить; этот набор может содержать предложения на английском языке, адреса электронной почты, команды TeX или что угодно. Затем вы можете задать такие вопросы, как «Соответствует ли строка шаблону?» Или «Есть ли совпадение с шаблоном где-нибудь в этой строке?». Вы также можете использовать RE для изменения строки или разделения её различными способами.

Шаблоны регулярных выражений компилируются в серию байт-кодов, выполняемыми написанным на C механизмом сопоставления. Для расширенного использования может потребоваться обратить особое внимание на то, как механизм будет выполнять данный RE, и записать RE в определенным образом, чтобы получить работающий быстрее байт-код. Оптимизация не рассматривается в этом документе, потому что для этого требуется хорошее понимание внутреннего устройства механизма сопоставления.

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

Простые шаблоны¶

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

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

Символы соответствия¶

Большинство букв и символов будут просто совпадать друг с другом. Например, регулярное выражение test будет точно соответствовать строке test . (Вы можете включить режим без учёта регистра, который позволит этому RE соответствовать Test или TEST ; подробнее об этом позже.)

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

Вот полный список метасимволов; их значение будет обсуждаться в оставшейся части этого HOWTO.

Первые метасимволы, которые мы рассмотрим, — это [ и ] . Они используются для указания класса символов, представляющий собой множество сопоставляемых символов. Символы можно перечислить по отдельности, или можно указать диапазон символов, указав два символа и разделив их знаком '-' . Например, [abc] будет соответствовать любому из символов a , b или c ; это то же самое, что и [a-c] , который использует диапазон для выражения того же множества символов. Если вы хотите сопоставить только строчные буквы, ваш RE будет [a-z] .

Метасимволы не активны внутри классов. Например, [akm$] будет соответствовать любому из символов 'a' , 'k' , 'm' или '$' ; '$' обычно является метасимволом, но внутри класса символов он лишён своей особой природы.

Вы можете сопоставить символы, не указанные в классе, по набору дополнений. На это указывает включение '^' в качестве первого символа класса. Например, [^5] будет соответствовать любому символу, кроме '5' . Если курсор появляется где-то ещё в классе символов, он не имеет особого значения. Например: [5^] будет соответствовать либо '5' , либо '^' .

Возможно, наиболее важным метасимволом является обратная косая черта \ . Как и в строковых литералах Python, за обратной косой чертой могут следовать различные символы для обозначения различных специальных последовательностей. Он также используется для экранирования всех метасимволов, чтобы вы по-прежнему могли сопоставлять их в шаблонах; например, если вам нужно сопоставить [ или \ , вы можете поставить перед ними обратную косую черту, чтобы удалить их особое значение: \[ или \\ .

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

Рассмотрим пример: \w соответствует любому буквенно-цифровому символу. Если шаблон регулярного выражения выражается в байтах, это эквивалентно классу [a-zA-Z0-9_] . Если шаблон регулярного выражения является строкой, \w будет соответствовать всем символам, помеченным как буквы в базе данных Юникод, предоставленной модулем unicodedata . Вы можете использовать более ограниченное определение \w в шаблоне строки, указав флаг re.ASCII при компиляции регулярного выражения.

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

\d Соответствует любой десятичной цифре; эквивалент класса [0-9] . \D Соответствует любому нецифровому символу; эквивалентно классу [^0-9] . \s Соответствует любому пробельному символу; эквивалентно классу [\t\n\r\f\v] . \S Соответствует любому непробельному символу; эквивалентно классу [^\t\n\r\f\v] . \w Соответствует любому буквенно-цифровому символу; эквивалент класса [a-zA-Z0-9_] . \W Соответствует любому не буквенно-цифровому символу; эквивалент класса [^a-zA-Z0-9_] .

Эти последовательности могут быть включены в класс символов. Например, [\s,.] — это класс символов, который будет соответствовать любому пробельному символу, либо ',' , либо '.' .

Последний метасимвол в этом разделе — . . Он соответствует чему угодно, кроме символа новой строки, и есть альтернативный режим ( re.DOTALL ), в котором он будет соответствовать даже символу новой строки. . часто используется там, где вы хотите сопоставить «любой символ».

Повторение материала¶

Возможность сопоставления различных наборов символов — это первое, что могут делать регулярные выражения, что уже невозможно с методами, доступными для строк. Однако, если бы это была единственная дополнительная возможность регулярных выражений, они не были бы большим достижением. Другая возможность заключается в том, что вы можете указать, что части RE должны повторяться определенное количество раз.

Первый метасимвол для повторения вещей, на которые мы будем смотреть — это * . * не соответствует литералу символа '*' ; вместо этого указывается, что предыдущий символ может быть сопоставлен ноль или более раз, а не ровно один раз.

Например, ca*t будет соответствовать 'ct' (0 символов 'a' ), 'cat' (1 'a' ), 'caaat' (3 символа 'a' ) и т. д.

Такие повторения, как * является жадным; при повторении RE механизм сопоставления будет пытаться повторить его столько раз, сколько возможно. Если более поздние части шаблона не совпадают, механизм сопоставления затем сделает резервную копию и попытается снова с меньшим количеством повторений.

Пошаговый пример сделает это более очевидным. Рассмотрим выражение a[bcd]*b . Это соответствует букве 'a' , нулю или нескольким буквам из класса [bcd] и, наконец, заканчивается 'b' . Теперь представьте сопоставление этого RE со строкой 'abcbd' .

Шаг Соответствие Объяснение
1 a a в RE соответствии.
2 abcbd Движок соответствия [bcd]* , просматривая в даль, как только можно, до конца строки.
3 Сбой Движок пытается соответствовать b , но текущее положение в конце строки, таким образом, это приведёт к ошибке.
4 abcb Вернуться назад, так, чтобы [bcd]* соответствовало на один символ меньше.
5 Сбой Попробовать b повторно, но текущее положение в последнем символе, который является 'd' .
6 abc Вернуться назад повторно, чтобы [bcd]* совпадал только с bc .
6 abcb Попробовать b повторно. На этот раз символ в текущей позиции равен 'b' , поэтому успешно.

Теперь достигнут конец RE, и он соответствует 'abcb' . Это демонстрирует, как механизм сопоставления поначалу заходит так далеко, как только может, и если совпадения не обнаружено, он будет постепенно выполнять резервное копирование и снова и снова повторять оставшуюся часть RE. Он будет выполнять резервное копирование до тех пор, пока он не попробует нулевые совпадения для [bcd]* , и если это впоследствии не удастся, механизм сделает вывод, что строка вообще не соответствует RE.

Другим повторяющимся метасимволом является + , который совпадает один или несколько раз. Внимательно проследите за различиями между * и + ; * совпадает ноль или более раз, поэтому то, что повторяется, может вообще отсутствовать, в то время как + требует по крайней мере одного раза. Чтобы использовать аналогичный пример, ca+t будет соответствовать 'cat' (1 'a' ), 'caaat' (3 'a' ), но не будет соответствовать 'ct' .

Есть ещё два повторяющихся квалификатора. Знак вопроса ? соответствует либо один раз, либо ноль раз; вы можете думать об этом как о пометке чего-либо как необязательного. Например, home-?brew соответствует либо 'homebrew' , либо 'home-brew' .

Самый сложный повторяющийся квалификатор — , где m и n — десятичные целые числа. Этот квалификатор означает, что должно быть не менее m повторений, но не более n. Например, a/b будет соответствовать 'a/b' , 'a//b' и 'a///b' . Он не будет соответствовать 'ab' , потому что у него нет косой черты, или 'a////b' , у которого их четыре.

Вы можете пропустить m или n; в этом случае для отсутствующего значения предполагается разумное значение. Отсутствие m интерпретируется как нижний предел 0, а пропуск n приводит к бесконечности верхней границы.

Читатели, склонные к редукционизму, могут заметить, что все три других квалификатора могут быть выражены с использованием этой нотации. то же, что и * , эквивалентно + , а то же, что и ? . Лучше использовать * , + или ? , когда можно, просто потому, что они короче и их проще читать.

Использование регулярных выражений¶

Теперь, когда мы рассмотрели несколько простых регулярных выражений, как на самом деле их использовать в Python? Модуль re предоставляет интерфейс к механизму регулярных выражений, позволяя вам компилировать RE в объекты, а затем выполнять сопоставления с ними.

Компилирование регулярных выражений¶

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

>>> import re >>> p = re.compile('ab*') >>> p re.compile('ab*') 

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

>>> p = re.compile('ab*', re.IGNORECASE) 

RE передаётся в re.compile() в виде строки. RE обрабатываются как строки, потому что регулярные выражения не являются частью основного языка Python, и для их выражения не был создан специальный синтаксис. (Есть приложения, которым вообще не нужны RE, поэтому нет необходимости раздувать языковую спецификацию, включая их.) Вместо этого модуль re — это просто модуль расширения C, включенный в Python, точно так же, как модули socket или zlib .

Размещение RE в строках упрощает язык Python, но имеет один недостаток, который является темой следующего раздела.

Чума обратной косой черты¶

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

Допустим, вы хотите написать соответствующий строке \section RE, которая может быть найдена в файле LaTeX. Чтобы выяснить, что писать в программном коде, начните с нужной сопоставляемой строки. Затем вы должны экранировать любые обратные косые черты и другие метасимволы, поставив перед ними обратную косую черту, в результате чего получится строка \\section . Результирующая строка, которую необходимо передать в re.compile() , должна быть \\section . Однако, чтобы выразить это как строковый литерал Python, необходимо снова экранировать обе обратные косые черты.

Символы Стадия
\section Текстовая строка для соответствия
\\section Экранирование обратного слеша для re.compile()
"\\\\section" Экранирование обратных слешей для строкового литерала

Короче говоря, чтобы соответствовать буквальной обратной косой черте, нужно написать '\\\\' как строку RE, потому что регулярное выражение должно быть \\ , а каждая обратная косая черта должна быть выражена как \\ внутри обычного строкового литерала Python. В RE, которые многократно используют обратную косую черту, это приводит к множеству повторяющихся обратных косых черт и затрудняет понимание результирующих строк.

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

Кроме того, специальные escape-последовательности, которые допустимы в регулярных выражениях, но недействительны в качестве строковых литералов Python, теперь приводят к DeprecationWarning и в конечном итоге станут SyntaxError , что означает, что последовательности будут недействительными, если необработанная строковая нотация или экранирование обратной косой черты не будут использоваться.

Обычная строка Сырая строка
"ab*" r"ab*"
"\\\\section" r"\\section"
"\\w+\\s+\\1" r"\w+\s+\1"

Выполнение соответствий¶

Что делать, когда у вас есть объект, представляющий скомпилированное регулярное выражение? У объектов-шаблонов есть несколько методов и атрибутов. Здесь будут рассмотрены только самые важные из них; полный список см. в документации re .

Метод/Атрибут Назначение
match() Определить, соответствует ли RE началу строки.
search() Просканировать строку и найти любое место соответствия RE.
findall() Найти все подстроки соответствующие RE и вернуть их в виде списка.
finditer() Найти все подстроки соответствующие RE и вернуть их как итератор .

match() и search() возвращают None , если совпадений не найдено. В случае успеха возвращается экземпляр объекта соответствия , содержащий информацию о совпадении: где оно начинается и заканчивается, сопоставленная подстрока и т. д.

Вы можете узнать об этом, экспериментируя в интерактивном режиме с модулем re . Если у вас есть tkinter , вы также можете посмотреть Tools/demo/redemo.py, демонстрационную программу, включенную в дистрибутив Python. Он позволяет вам вводить RE и строки и показывает, соответствует RE или нет. redemo.py может оказаться весьма полезным при отладке сложного RE.

В этом HOWTO в качестве примеров используется стандартный интерпретатор Python. Сначала запустите интерпретатор Python, импортируйте модуль re и скомпилируйте RE:

>>> import re >>> p = re.compile('[a-z]+') >>> p re.compile('[a-z]+') 

Теперь вы можете попробовать сопоставить различные строки с RE [a-z]+ . Пустая строка вообще не должна совпадать, поскольку + означает «одно или несколько повторений». В этом случае match() должен вернуть None , что приведет к тому, что интерпретатор не выведет никаких результатов. Вы можете явно распечатать результат match() , чтобы прояснить это.

>>> p.match("") >>> print(p.match("")) None 

Теперь давайте попробуем его на строке, которая должна соответствовать, например tempo . В этом случае match() вернёт объект соответствия , поэтому вам следует сохранить результат в переменной для дальнейшего использования.

>>> m = p.match('tempo') >>> m

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

Метод/Атрибут Назначение
group() Возвращает строку, совпадающую с RE
start() Возвращает стартовую позицию соответствия
end() Возвращает конечную позицию соответствия
span() Возвращает кортеж, содержащий (начальные, конечные) позиции соответствия

Эти методы вскоре прояснят их смысл:

>>> m.group() 'tempo' >>> m.start(), m.end() (0, 5) >>> m.span() (0, 5) 

group() возвращает подстроку, сопоставленную RE. start() и end() возвращают начальный и конечный индексы соответствия. span() возвращает как начальный, так и конечный индексы в одном кортеже. Поскольку метод match() проверяет только совпадение RE в начале строки, start() всегда будет нулевым. Однако метод шаблонов search() просматривает строку, поэтому в этом случае совпадение может не начинаться с нуля.

>>> print(p.match('. message')) None >>> m = p.search('. message'); print(m) >>> m.group() 'message' >>> m.span() (4, 11) 

В реальных программах наиболее распространенный стиль — сохранить объект соответствия в переменной, а затем проверить, было ли это None . Обычно выглядит так:

p = re.compile( . ) m = p.match( 'string goes here' ) if m: print('Match found: ', m.group()) else: print('No match') 

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

>>> p = re.compile(r'\d+') >>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping') ['12', '11', '10'] 

Префикс r , делающий литерал необработанным строковым литералом, необходим в этом примере, потому что escape-последовательности в обычном «приготовленном» строковом литерале, которые не распознаются Python, в отличие от регулярных выражений, теперь приводят к DeprecationWarning и в конечном итоге станут SyntaxError . См. Чума обратной косой черты .

findall() должен создать весь список, прежде чем его можно будет вернуть в качестве результата. Метод finditer() возвращает последовательность экземпляров объект соответствия как итератор :

>>> iterator = p.finditer('12 drummers drumming, 11 . 10 . ') >>> iterator >>> for match in iterator: . print(match.span()) . (0, 2) (22, 24) (29, 31) 

Функции уровня модуля¶

Вам не нужно создавать объект шаблона и вызывать его методы; модуль re также предоставляет функции верхнего уровня, называемые match() , search() , findall() , sub() и т. д. Эти функции принимают те же аргументы, что и соответствующий метод шаблона со строкой RE, добавленной в качестве первого аргумента, и по-прежнему возвращают либо None , либо экземпляр объект соответствия .

>>> print(re.match(r'From\s+', 'Fromage amk')) None >>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998')

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

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

Флаги компиляции¶

Флаги компиляции позволяют изменять некоторые аспекты работы регулярных выражений. Флаги доступны в модуле re под двумя именами: длинным именем, например IGNORECASE , и короткой однобуквенной формой, например I . (Если вы знакомы с модификаторами шаблонов Perl, однобуквенные формы используют одни и те же буквы; краткая форма re.VERBOSE , например, re.X .) Несколько флагов могут быть указаны с помощью побитового ИЛИ; например, re.I | re.M устанавливает флаги I и M .

Вот таблица доступных флагов с более подробным объяснением каждого из них.

Флаг Значение
ASCII , A Сделать некоторые экранированные символы, подобные \w , \b , \s и \d , с особым свойством, соответствовать обычным ASCII символам.
DOTALL , S Сделать . совпадающим с любым символом, включая новые строки.
IGNORECASE , I Выполнить нечувствительные к регистру совпадения.
LOCALE , L Выполнить совпадение с учётом локали.
MULTILINE , M Многострочное сопоставление, влияющее на ^ и $ .
VERBOSE , X (for „extended“) Включить подробные RE, которые могут быть более человекочитаемыми и понятными.

I IGNORECASE

Выполнять сопоставление без учёта регистра; символьные классы и буквальные строки будут соответствовать буквам без учёта регистра. Например, [A-Z] также будет соответствовать строчным буквам. Полное Юникод сопоставление также работает, если не используется флаг ASCII для отключения совпадений, отличных от ASCII. Когда Юникод шаблоны [a-z] или [A-Z] используются в сочетании с флагом IGNORECASE , они будут соответствовать 52 буквам ASCII и 4 дополнительным буквам, отличным от ASCII: „İ“ (U+0130, латинская заглавная буква I с точкой выше), „ı „(U+0131, латинская строчная буква без точки i), „ſ“ (U+017F, латинская строчная длинная буква s) и „K“ (U+212A, знак кельвина). Spam будет соответствовать 'Spam' , 'spam' , 'spAM' или 'ſpam' (последний соответствует только в режиме Юникод). Этот нижний регистр не учитывает текущий языковой стандарт; это будет, если вы также установите флаг LOCALE .

Сделать \w , \W , \b , \B и сопоставление без учета регистра зависимыми от текущего языкового стандарта, а не от базы данных Юникод.

Локали — это функция библиотеки C, предназначенная для помощи в написании программ, учитывающих языковые различия. Например, если вы обрабатываете закодированный французский текст, вам нужна возможность писать \w+ для сопоставления слов, но \w соответствует только классу символов [A-Za-z] в байтовых шаблонах; он не будет соответствовать байтам, соответствующим é или ç . Если ваша система настроена правильно и выбрана французская локаль, некоторые функции C сообщат программе, что байт, соответствующий é , также следует рассматривать как букву. Установка флага LOCALE при компиляции регулярного выражения приведёт к тому, что полученный скомпилированный объект будет использовать эти функции C для \w ; это медленнее, но также позволяет \w+ соответствовать французским словам, как и следовало ожидать. Использование этого флага не рекомендуется в Python 3, поскольку механизм локали очень ненадежен, он обрабатывает только одну «культуру» за раз и работает только с 8-битными языковыми стандартами. Сопоставление Юникод уже включено по умолчанию в Python 3 для Юникод шаблонов (str), и оно может обрабатывать различные локали/языки.

( ^ и $ ещё не объяснены; они будут представлены в разделе Больше метасимволов .)

Обычно ^ соответствует только в начале строки, а $ соответствует только в конце строки и непосредственно перед новой строкой (если есть) в конце строки. Когда этот флаг указан, ^ соответствует началу строки и началу каждой строки в строке, сразу после каждой новой строки. Точно так же метасимвол $ соответствует либо в конце строки, либо в конце каждой строки (непосредственно перед каждой новой строкой).

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

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

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

Например, вот RE, использующий re.VERBOSE ; видите, насколько легче читать?

charref = re.compile(r""" &[#] # Начало ссылки на числовой объект ( 0[0-7]+ # Восьмеричная форма | [0-9]+ # Десятичная форма | x[0-9a-fA-F]+ # Шестнадцатеричная форма ) ; # Завершающая точка с запятой """, re.VERBOSE) 

Без настройки подробностей RE выглядел бы так:

charref = re.compile("&#(0[0-7]+" "|[0-9]+" "|x[0-9a-fA-F]+);") 

В приведенном выше примере автоматическая конкатенация строковых литералов Python использовалась для разделения RE на более мелкие части, но это всё ещё труднее понять, чем версию, использующую re.VERBOSE .

Более продвинутые шаблоны¶

Пока что мы рассмотрели только часть возможностей регулярных выражений. В этом разделе мы расскажем о некоторых новых метасимволах и о том, как использовать группы для извлечения фрагментов сопоставленного текста.

Больше метасимволов¶

Есть некоторые метасимволы, которые мы ещё не рассмотрели. Большинство из них будет рассмотрено в этом разделе.

Некоторые из оставшихся метасимволов, которые следует обсудить, — это утверждения нулевой ширины. Они не заставляют двигатель двигаться по строке; вместо этого они вообще не потребляют символов, а просто преуспевают или проигрывают. Например, \b — это утверждение, что текущая позиция находится на границе слова; позиция не меняется на \b вообще. Это означает, что утверждения нулевой ширины никогда не должны повторяться, потому что, если они совпадают один раз в заданном месте, они, очевидно, могут быть сопоставлены бесконечное количество раз.

Чередование, или оператор «или». Если A и B — регулярные выражения , A|B будет соответствовать любой строке, которая соответствует либо A, либо B. | имеет очень низкий приоритет, чтобы он работал разумно, когда вы чередуете многосимвольные строки. Crow|Servo будет соответствовать либо 'Crow' , либо 'Servo' , а не 'Cro' , 'w' , 'S' и 'ervo' .

Чтобы соответствовать литералу '|' , используйте \| или заключите его в класс символов, как в [|] .

Соответствует началу строк. Если только не был флаг MULTILINE установлен, это будет соответствовать только в начале строки. В MULTILINE режиме, это также соответствует сразу после каждой новой строки в строке.

Например, если вы хотите сопоставить слово From только в начале строки, используйте RE ^From .

>>> print(re.search('^From', 'From Here to Eternity')) >>> print(re.search('^From', 'Reciting From Memory')) None 

Чтобы соответствовать буквальному '^' , используйте \^ .

Соответствует концу строки или любое место, за которым следует символ новой строки.

>>> print(re.search('>$', ' ')) '> >>> print(re.search('>$', '  ')) None >>> print(re.search('>$', ' \n')) '> 

Чтобы соответствовать литералу '$' , используйте \$ или заключите его в класс символов, как в [$] .

\A Соответствует только началу строки. Когда не в режиме MULTILINE , \A и ^ фактически одинаковы. В режиме MULTILINE они другое: \A по-прежнему соответствует только в начале строки, но ^ может соответствовать в любом месте внутри строки, следующей за символом новой строки. \Z Соответствует только концу строки. \b

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

Следующий пример соответствует class только тогда, когда это полное слово; он не будет соответствовать, если он содержится в другом слове.

>>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) None 

При использовании этой особой последовательности следует помнить о двух тонкостях. Во-первых, это наихудшее столкновение между строковыми литералами Python и последовательностями регулярных выражений. В строковых литералах Python \b — это символ возврата, значение ASCII 8. Если вы не используете необработанные строки, Python преобразует \b в символ возврата, и ваш RE не будет соответствовать ожидаемому. Следующий пример выглядит так же, как наш предыдущий RE, но пропускает 'r' перед строкой RE.

>>> p = re.compile('\bclass\b') >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b'))

Во-вторых, внутри символьного класса, где это утверждение не используется, \b представляет символ обратного пробела для совместимости со строковыми литералами Python.

\B Ещё одно утверждение нулевой ширины, оно противоположно \b , соответствует только тогда, когда текущая позиция не на границе слова.

Группировка¶

Часто вам нужно получить больше информации, чем просто совпадение RE. Регулярные выражения часто используются для анализа строк путём написания RE, разделенного на несколько подгрупп, которые соответствуют различным интересующим компонентам. Например, строка заголовка RFC-822 делится на имя заголовка и значение, разделенные ':' , например:

From: [email protected] User-Agent: Thunderbird 1.5.0.9 (X11/20061227) MIME-Version: 1.0 To: [email protected] 

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

Группы помечаются метасимволами '(' , ')' . '(' и ')' имеют почти то же значение, что и в математических выражениях; они группируют содержащиеся внутри выражения, и вы можете повторить содержимое группы с повторяющимся квалификатором, например * , + , ? или . Например, (ab)* будет соответствовать нулю или более повторов ab .:

>>> p = re.compile('(ab)*') >>> print(p.match('ababababab').span()) (0, 10) 

Группы, обозначенные как '(' , ')' , также фиксируют начальный и конечный индекс текста, которому они соответствуют; это можно получить, передав аргумент в group() , start() , end() и span() . Группы нумеруются, начиная с 0. Группа 0 присутствует всегда; это весь RE, поэтому все методы объект соответствия содержат группу 0 в качестве аргумента по умолчанию. Позже мы увидим, как выразить не охватывающие диапазон текста группы, которому они соответствуют.

>>> p = re.compile('(a)b') >>> m = p.match('ab') >>> m.group() 'ab' >>> m.group(0) 'ab' 

Подгруппы нумеруются слева направо, начиная с 1. Группы могут быть вложенными; чтобы определить число, просто сосчитайте открывающие скобки слева направо.

>>> p = re.compile('(a(b)c)d') >>> m = p.match('abcd') >>> m.group(0) 'abcd' >>> m.group(1) 'abc' >>> m.group(2) 'b' 

В group() можно передавать несколько номеров групп за раз, и в этом случае он вернёт кортеж, содержащий соответствующие значения для этих групп.

>>> m.group(2,1,2) ('b', 'abc', 'b') 

Метод groups() возвращает кортеж, содержащий строки для всех подгрупп, от 1 до их количества.

>>> m.groups() ('abc', 'b') 

Обратные ссылки в шаблоне позволяют указать, что содержимое более ранней группы захвата также должно быть найдено в текущем месте в строке. Например, \1 будет успешным, если точное содержимое группы 1 может быть найдено в текущей позиции, и не удастся в противном случае. Помните, что строковые литералы Python также используют обратную косую черту, за которой следуют числа, чтобы разрешить включение произвольных символов в строку, поэтому обязательно используйте необработанную строку при включении обратных ссылок в RE.

Например, следующий RE обнаруживает удвоенные слова в строке.

>>> p = re.compile(r'\b(\w+)\s+\1\b') >>> p.search('Paris in the the spring').group() 'the the' 

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

Незахватываемые и именованные группы¶

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

Perl 5 хорошо известен своими мощными дополнениями к стандартным регулярным выражениям. Для этих новых функций разработчики Perl не могли выбрать новые метасимволы для однократного нажатия клавиши или новые специальные последовательности, начинающиеся с \ , без того, чтобы регулярные выражения Perl не сильно отличались от стандартных RE. Если бы они выбрали & в качестве нового метасимвола, например, старые выражения предполагали бы, что & был обычным символом, и не смогли бы избежать его, написав \& или [&] .

Разработчики Perl выбрали решение использовать (. ) в качестве синтаксиса расширения. ? сразу после круглой скобки был синтаксической ошибкой, потому что ? нечего было бы повторять, поэтому это не создавало никаких проблем с совместимостью. Символы сразу после ? указывают, какое расширение используется, поэтому (?=foo) — это одно (утверждение положительного просмотра вперед), а (?:foo) — это другое (не захватывающая группа, содержащая подвыражение foo ).

Python поддерживает несколько расширений Perl и добавляет синтаксис расширения к синтаксису расширений Perl. Если первый символ после вопросительного знака — P , вы знаете, что это расширение, специфичное для Python.

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

Иногда вам нужно использовать группу для обозначения части регулярного выражения, но вы не заинтересованы в получении содержимого группы. Вы можете сделать этот факт явным, используя группу без захвата: (. ) , где вы можете заменить . любым другим регулярным выражением.

>>> m = re.match("([abc])+", "abc") >>> m.groups() ('c',) >>> m = re.match("(?:[abc])+", "abc") >>> m.groups() () 

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

Более важной особенностью являются именованные группы: вместо того, чтобы ссылаться на них по номерам, на группы можно ссылаться по имени.

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

>>> p = re.compile(r'(?P\b\w+\b)') >>> m = p.search( '(((( Lots of punctuation )))' ) >>> m.group('word') 'Lots' >>> m.group(1) 'Lots' 

Кроме того, вы можете получить именованные группы в виде словаря с помощью groupdict() :

>>> m = re.match(r'(?P\w+) (?P\w+)', 'Jane Doe') >>> m.groupdict()

Именованные группы удобны, потому что позволяют использовать легко запоминающиеся имена вместо того, чтобы запоминать числа. Вот пример RE из модуля imaplib :

InternalDate = re.compile(r'INTERNALDATE "' r'(?P[ 123][0-9])-(?P[A-Z][a-z][a-z])-' r'(?P[0-9][0-9][0-9][0-9])' r' (?P[0-9][0-9]):(?P[0-9][0-9]):(?P[0-9][0-9])' r' (?P[-+])(?P[0-9][0-9])(?P[0-9][0-9])' r'"') 

Очевидно, что гораздо проще получить m.group('zonem') , чем не забывать извлекать группу 9.

Синтаксис обратных ссылок в выражении, таком как (. )\1 , относится к номеру группы. Естественно, существует вариант, в котором вместо номера используется название группы. Это ещё одно расширение Python: (?P=name) указывает, что содержимое группы с именем name должно снова совпадать в текущей точке. Регулярное выражение для поиска удвоенных слов \b(\w+)\s+\1\b также можно записать как \b(?P\w+)\s+(?P=word)\b :

>>> p = re.compile(r'\b(?P\w+)\s+(?P=word)\b') >>> p.search('Paris in the the spring').group() 'the the' 

Утверждения с опережением¶

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

(?=. ) Утверждение положительного просмотра вперед. Это выполняется успешно, если содержащееся в нем регулярное выражение, представленное здесь как . , успешно совпадает в текущем местоположении, и не работает в противном случае. Но после того, как содержащееся выражение было опробовано, механизм сопоставления вообще не продвигается; остальная часть шаблона проверяется прямо там, где началось утверждение. (. ) Утверждение отрицательного просмотра вперед. Это противоположно положительному утверждению; оно считается успешным, если содержащееся выражение не совпадает с текущей позицией в строке.

Чтобы добавить понятности, давайте рассмотрим случай, когда полезен просмотр вперед. Рассмотрим простой шаблон для сопоставления имени файла и разделения его на базовое имя и расширение, разделенные . . Например, в news.rc news — это базовое имя, а rc — это расширение имени файла.

Соответствующий шаблон довольно прост:

Обратите внимание, что . требует особой обработки, потому что это метасимвол, поэтому он находится внутри класса символов, чтобы соответствовать только этому символу. Также обратите внимание на завершающий $ ; он добавляется, чтобы гарантировать, что вся остальная часть строки должна быть включена в расширение. Это регулярное выражение соответствует foo.bar и autoexec.bat , а также sendmail.cf и printers.conf .

Теперь подумайте об усложнении проблемы; что, если вы хотите сопоставить имена файлов с расширением, отличным от bat ? Несколько неверных попыток:

.*[.][^b].*$ первая попытка выше пытается исключить bat , требуя, чтобы первый символ расширения не был b . Это неверно, потому что шаблон также не соответствует foo.bar .

Выражение становится более запутанным, когда вы пытаетесь исправить первое решение, требуя соответствия в одном из следующих случаев: первый символ расширения не b ; второй символ не a ; или третий символ не t . Это принимает foo.bar и отклоняет autoexec.bat , но требует трехбуквенного расширения и не принимает имя файла с двухбуквенным расширением, например sendmail.cf . Мы снова усложним шаблон, чтобы исправить это.

В третьей попытке вторая и третья буквы делаются необязательными, чтобы разрешить сопоставление расширений короче трех символов, например sendmail.cf .

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

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

.*[.](?!bat$)[^.]*$ отрицательный просмотр вперед означает: если выражение bat не соответствует в этой точке, попробуйте остальную часть шаблона; если bat$ действительно совпадает, весь шаблон завершится ошибкой. Завершающий $ необходим, чтобы гарантировать, что будет разрешено что-то вроде sample.batch , где расширение начинается только с bat . [^.]* гарантирует, что шаблон работает, когда в имени файла есть несколько точек.

Исключить другое расширение имени файла теперь просто; просто добавьте его как альтернативу внутри утверждения. Следующий шаблон исключает имена файлов, заканчивающиеся на bat или exe :

Изменение строк¶

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

Метод/Атрибут Цель
split() Разделить строку на список, разбив её там, где есть соответствие RE
sub() Найти все подстроки, где RE совпадает и заменить их другую строку
subn() Делает то же самое, что и sub() , но возвращает новую строку и количество замен

Разделение строк¶

Метод split() шаблона разделяет строку на части, когда RE совпадает, возвращая список частей. Он похож на метод строк split() , но обеспечивает гораздо более универсальные разделители, которые можно разделять; строка split() поддерживает разделение только пробелами или фиксированной строкой. Как и следовало ожидать, есть функция re.split() на уровне модуля.

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

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

>>> p = re.compile(r'\W+') >>> p.split('This is a test, short and sweet, of split().') ['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', ''] >>> p.split('This is a test, short and sweet, of split().', 3) ['This', 'is', 'a', 'test, short and sweet, of split().'] 

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

>>> p = re.compile(r'\W+') >>> p2 = re.compile(r'(\W+)') >>> p.split('This. is a test.') ['This', 'is', 'a', 'test', ''] >>> p2.split('This. is a test.') ['This', '. ', 'is', ' ', 'a', ' ', 'test', '.', ''] 

Функция уровня модуля re.split() добавляет RE, который будет использоваться в качестве первого аргумента, но в остальном остается неизменным.

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

Поиск и замена¶

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

Возвращает строку, полученную заменой крайних левых неперекрывающихся вхождений RE в string замещающей replacement. Если шаблон не найден, string возвращается без изменений.

Необязательный аргумент count — это максимальное количество заменяемых экземпляров шаблона; count должно быть неотрицательным целым числом. Значение по умолчанию 0 означает замену всех вхождений.

Далее простой пример использования метода sub() . Он заменяет названия цветов словом colour :

>>> p = re.compile('(blue|white|red)') >>> p.sub('colour', 'blue socks and red shoes') 'colour socks and colour shoes' >>> p.sub('colour', 'blue socks and red shoes', count=1) 'colour socks and red shoes' 

Метод subn() выполняет ту же работу, но возвращает кортеж из двух элементов, содержащий новое строковое значение и количество выполненных замен:

>>> p = re.compile('(blue|white|red)') >>> p.subn('colour', 'blue socks and red shoes') ('colour socks and colour shoes', 2) >>> p.subn('colour', 'no colours at all') ('no colours at all', 0) 

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

>>> p = re.compile('x*') >>> p.sub('-', 'abxd') '-a-b--d-' 

Если replacement является строкой, обрабатываются любые экранирующие символы обратной косой черты. Т. е. \n преобразуется в одиночный символ новой строки, \r преобразуется в возврат каретки и т. д. Неизвестные экранирующие символы, такие как \& , остаются в покое. Обратные ссылки, такие как \6 , заменяются подстрокой, соответствующей группе в RE. Это позволяет включать части исходного текста в результирующую строку замены.

Далее пример соответствует слову section , за которым следует строка, заключенная в < , >, и изменяет section на subsection :

>>> p = re.compile('section< ( [^>]* ) >', re.VERBOSE) >>> p.sub(r'subsection<\1>','section  section ') 'subsection subsection' 

Также существует синтаксис для ссылки на именованные группы, как определено синтаксисом (?P. ) . \g будет использовать подстроку, совпадающую с группой с именем name , а \g использует соответствующий номер группы. Следовательно, \g эквивалентен \2 , но не является двусмысленным в строке замены, такой как \g0 . ( \20 будет интерпретироваться как ссылка на группу 20, а не как ссылку на группу 2, за которой следует буквальный символ '0' .) Все следующие замены эквивалентны, но используют все три варианта строки замены.

>>> p = re.compile('section < (?P[^>]* ) >', re.VERBOSE) >>> p.sub(r'subsection<\1>','section ') 'subsection' >>> p.sub(r'subsection<\g<1>>','section ') 'subsection' >>> p.sub(r'subsection<\g>','section ') 'subsection' 

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

В следующем примере функция замены переводит десятичные числа в шестнадцатеричные:

>>> def hexrepl(match): . "Возвращает шестнадцатеричную строку для десятичного числа" . value = int(match.group()) . return hex(value) . >>> p = re.compile(r'\d+') >>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.') 'Call 0xffd2 for printing, 0xc000 for user code.' 

При использовании функции re.sub() на уровне модуля шаблон передаётся в качестве первого аргумента. Шаблон может быть представлен как объект или как строка; если вам нужно указать флаги регулярного выражения, вы должны либо использовать объект шаблона в качестве первого параметра, либо использовать встроенные модификаторы в строке шаблона, например sub("(?i)b+", "x", "bbbb BBBB") возвращает 'x x' .

Общие проблемы¶

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

Использование методов строки¶

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

Одним из примеров может быть замена одной фиксированной строки другой; например, вы можете заменить word на deed . re.sub() кажется подходящей функцией, но рассмотрим метод replace() . Обратите внимание, что replace() также заменит word внутри слов, превратив swordfish в sdeedfish , но наивный RE word тоже сделал бы это. (Чтобы избежать выполнения подстановки частей слов, шаблон должен быть \bword\b , чтобы требовать, чтобы word имел границу слова с обеих сторон. Это выходит за рамки возможностей replace() .)

Другой распространенной задачей является удаление каждого вхождения одного символа из строки или замена его другим отдельным символом. Вы можете сделать это с помощью чего-то вроде re.sub('\n', ' ', S) , но translate() может выполнять обе задачи и будет быстрее, чем любая операция с регулярным выражением.

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

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

Функция match() только проверяет совпадение RE с началом строки, в то время как search() просматривает строку в поисках совпадения. Важно помнить об этом различии. Помните, что match() сообщит только об успешном совпадении, которое начнется с 0; если совпадение не начнется с нуля, match() не сообщит об этом.

>>> print(re.match('super', 'superstition').span()) (0, 5) >>> print(re.match('super', 'insuperable')) None 

С другой стороны, search() просканирует строку вперед, сообщая о первом найденном совпадении.

>>> print(re.search('super', 'superstition').span()) (0, 5) >>> print(re.search('super', 'insuperable').span()) (2, 7) 

Иногда у вас возникнет соблазн продолжить использовать re.match() и просто добавить .* в начало RE. Не поддавайтесь этому искушению и используйте вместо него re.search() . Компилятор регулярных выражений выполняет некоторый анализ RE, чтобы ускорить процесс поиска совпадения. Один такой анализ выясняет, каким должен быть первый символ совпадения; например, шаблон, начинающийся с Crow , должен соответствовать шаблону, начинающемуся с 'C' . Анализ позволяет механизму быстро сканировать строку в поисках начального символа, пытаясь найти полное совпадение, только если найдено 'C' .

Добавление .* отменяет эту оптимизацию, требуя сканирования до конца строки, а затем возврата, чтобы найти совпадение для остальной части RE. Вместо этого используйте re.search() .

Жадный против нежадного¶

При повторении регулярного выражения, как в a* , результирующим действием является использование как можно большей части шаблона. Этот факт часто обманывает вас, когда вы пытаетесь сопоставить пару сбалансированных разделителей, таких как угловые скобки, окружающие тег HTML. Наивный шаблон для сопоставления одного тега HTML не работает из-за жадной природы .* .

>>> s = 'Title' >>> len(s) 32 >>> print(re.match('<.*>', s).span()) (0, 32) >>> print(re.match('<.*>', s).group()) Title 

RE соответствует '' , а .* потребляет остальную часть строки. Однако в RE осталось еще больше, и > не может соответствовать в конце строки, поэтому обработчик регулярных выражений должен выполнять обратный поиск символ за символом, пока не найдёт совпадение для > . Окончательное совпадение простирается от '' до '>' в '' , что вам не нужно.

В этом случае решением является использование нежадных квалификаторов *? , +? , ?? или ? , которые соответствуют как можно меньшему количеству текста. В приведенном выше примере '>' проверяется сразу после первых совпадений '' на каждом шаге. Это дает правильный результат:

>>> print(re.match('<.*?>', s).group())

(Обратите внимание, что парсинг HTML или XML с помощью регулярных выражений является болезненным. Быстрые и грязные шаблоны будут обрабатывать общие случаи, но HTML и XML содержат особые нарушающие очевидное регулярное выражение случаи; к тому времени, когда вы напишете обрабатывающее все возможные случаи регулярное выражение, шаблоны будут очень сложными. Для таких задач используйте модуль парсинга HTML или XML.)

Использование re.VERBOSE¶

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

Для таких RE указание флага re.VERBOSE при компиляции регулярного выражения может быть полезным, поскольку он позволяет более чётко отформатировать регулярное выражение.

У флага re.VERBOSE есть несколько эффектов. Пробелы в регулярном выражении, не входящие в класс символов, игнорируются. Это означает, что такое выражение, как dog | cat , эквивалентно менее читаемому dog|cat , но [a b] по-прежнему будет соответствовать символам 'a' , 'b' или пробелу. Кроме того, вы также можете помещать комментарии в RE; комментарии простираются от символа # до следующей новой строки. При использовании со строками, заключенными в тройные кавычки, это позволяет более аккуратно форматировать RE:

pat = re.compile(r""" \s* # Пропустить ведущие пробелы (?P[^:]+) # Имя заголовка \s* : # Пробел и двоеточие (?P.*?) # Значение заголовка - *? используется для # потери следующего конечного пробела \s*$ # Конечный пробел до конца строки """, re.VERBOSE) 

Это гораздо более читабельно, чем:

pat = re.compile(r"\s*(?P[^:]+)\s*:(?P.*?)\s*$") 

Обратная связь¶

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

Самая полная книга по регулярным выражениям — почти наверняка «Освоение регулярных выражений» Джеффри Фридла, изданная O’Reilly. К сожалению, он сконцентрирован исключительно на разновидностях регулярных выражений Perl и Java и вообще не содержит материалов о Python, поэтому он не будет полезен в качестве справочника для программирования на Python. (Первое издание охватывало теперь удаленный модуль Python regex , который вам не очень поможет.) Попробуйте проверить его из своей библиотеки.

Шпаргалка по регулярным выражениям. В примерах

Регулярные выражения (regex или regexp) очень эффективны для извлечения информации из текста. Для этого нужно произвести поиск одного или нескольких совпадений по определённому шаблону (т. е. определённой последовательности символов ASCII или unicode).

Области применения regex разнообразны, от валидации до парсинга/замены строк, передачи данных в другие форматы и Web Scraping’а.

Одна из любопытных особенностей регулярных выражений в их универсальности, стоит вам выучить синтаксис, и вы сможете применять их в любом (почти) языке программирования (JavaScript, Java, VB, C #, C / C++, Python, Perl, Ruby, Delphi, R, Tcl, и многих других). Небольшие отличия касаются только наиболее продвинутых функций и версий синтаксиса, поддерживаемых движком.

Давайте начнём с нескольких примеров.

Основы

Якоря — ^ и $

^Привет соответствует строке, начинающейся с Привет -> тестпока$ соответствует строке, заканчивающейся на пока^Привет пока$ точное совпадение (начинается и заканчивается как Привет пока)воробушки соответствует любой строке, в которой есть текст воробушки

Квантификаторы — * + ? и <>

abc* соответствует строке, в которой после ab следует 0 или более символов c -> тестabc+ соответствует строке, в которой после ab следует один или более символов cabc? соответствует строке, в которой после ab следует 0 или один символ cabc соответствует строке, в которой после ab следует 2 символа cabc соответствует строке, в которой после ab следует 2 или более символов cabc соответствует строке, в которой после ab следует от 2 до 5 символов ca(bc)* соответствует строке, в которой после ab следует 0 или более последовательностей символов bca(bc) соответствует строке, в которой после ab следует от 2 до 5 последовательностей символов bc

Оператор ИЛИ — | или []

a(b|c) соответствует строке, в которой после a следует b или c -> тестa[bc] как и в предыдущем примере

Символьные классы — \d \w \s и .

\d соответствует одному символу, который является цифрой -> тест\w соответствует слову (может состоять из букв, цифр и подчёркивания) -> тест\s соответствует символу пробела (включая табуляцию и прерывание строки). соответствует любому символу -> тест

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

У операторов \d , \w и \s также есть отрицания ― \D, \W и \S соответственно.

Например, оператор \D будет искать соответствия противоположенные \d .

Непечатаемые символы также можно искать, например табуляцию \t , новую строку \n , возврат каретки \r .

Флаги

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

Регулярное выражение, как правило, записывается в такой форме / abc /, где шаблон для сопоставления выделен двумя слешами / . В конце выражения, мы определяем значение флага (эти значения можно комбинировать):

  • g (global) ― не возвращает результат после первого совпадения, а продолжает поиск с конца предыдущего совпадения.
  • m (multi line) ― с таким флагом, операторы ^ и $ вызовут совпадение в начале и конце строки ввода (line), вместо строки целиком (string).
  • i (insensitive) ― делает выражение регистронезависимым (например, /aBc/i соответствует AbC).

Средний уровень

Скобочные группы ― ()

a(bc) создаём группу со значением bc -> тестa(?:bc)* оперетор ?: отключает группу -> тестa(?bc) так, мы можем присвоить имя группе -> тест

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

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

Скобочные выражения ― []

[abc] соответствует строке, которая содержит либо символ a или a b или a c -> такой же эффект от a|b|c -> тест[a-c] то же, что и выше[a-fA-F0–9] строка, представляющая одну шестнадцатеричную цифру без учёта регистра -> тест[0–9]% строка, содержащая символ от 0 до 9 перед знаком %[^a-zA-Z] строка, которая не имеет буквы от a до z или от A до Z. В этом случае ^ используется как отрицание в выражении -> тест

Помните, что внутри скобочных выражений все специальные символы (включая обратную косую черту \ ) теряют своё служебное значение, поэтому нам ненужно их экранировать.

Жадные и ленивые сопоставления

Квантификаторы ( * + <> ) ― это «жадные» операторы, потому что они продолжают поиск соответствий, как можно глубже ― через весь текст.

Например, выражение <.+>соответствует

simple div

в This is a

simple div

test . Чтобы найти только тэг div ― можно использовать оператор ? , сделав выражение «ленивым»:

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

Продвинутый уровень

Границы слов ― \b и \B

\b ― соответствует границе слова, наподобие якоря (он похож на $ и ^ ), где предыдущий символ ― словесный (например, \w ), а следующий ― нет, либо наоборот, (например, это может быть начало строки или пробел).

\B ― соответствует несловообразующей границе. Соответствие не должно обнаруживаться на границе \b .

Обратные ссылки — \1

([abc])\1 \1 соответствует тексту из первой захватываемой группы -> тест([abc])([de])\2\1 можно использовать \2 (\3, \4, и т.д.) для определения порядкового номера захватываемой группы -> тест(? [abc])\k мы присвоили имя foo группе, и теперь ссылаемся на неё используя ― (\k ). Результат, как и в первом выражении -> тест

Опережающие и ретроспективные проверки — (?=) and (?<=)

d(?=r) соответствует d, только если после этого следует r, но r не будет входить в соответствие выражения -> тест(?r)d соответствует d, только если перед этим есть r, но r не будет входить в соответствие выражения -> тест

Вы можете использовать оператор отрицания !

d(?!r) соответствует d, только если после этого нет r, но r не будет входить в соответствие выражения -> тест(?r)d соответствует d, только если перед этим нет r, но r не будет входить в соответствие выражения -> тест

Заключение

Как вы могли убедиться, области применения регулярных выражений разнообразны. Я уверен, что вы сталкивались с похожими задачами в своей работе (хотя бы с одной из них), например такими:

  • Валидация данных (например, правильно ли заполнена строка time)
  • Сбор данных (особенно веб-скрапинг, поиск страниц, содержащих определённый набор слов в определённом порядке)
  • Обработка данных (преобразование сырых данных в нужный формат)
  • Парсинг (например, достать все GET параметры из URL или текст внутри скобок)
  • Замена строк (даже во время написания кода в IDE, можно, например преобразовать Java или C# класс в соответствующий JSON объект, заменить “;” на “,”, изменить размер букв, избегать объявление типа и т.д.)
  • Подсветка синтаксиса, переименование файла, анализ пакетов и многие другие задачи, где нужно работать со строками (где данные не должны быть текстовыми).

Удалить символ регулярным выражением в словаре

Здравствуйте.
Как можно с помощью регулярного выражения удалить точку в конце слова в словаре?

1 2 3 4 5 6
data = { 'key_1': 'test.', 'key_2': te.st', 'key_3': '.test', 'key_4': 'test' >

Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

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

Проблемы с регулярным выражением
Имеется часть кода (взял с гита, переделываю под себя), не пойму почему регулярное выражение.

Обработка файлов регулярным выражением
подскажите как написать обработку файлов регулярным выражением? программа должна открыть все файлы.

Символ > принимается регулярным выражением как буква-цифра
Символ > принимается регулярным выражением как буква-цифра. Регулярное выражение такое: regex.

Регулярным выражением удалить кусок кода из файлов
Нужно с помощью регулярного выражения в VisualStudio удалить вот такой кусок кода.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *