Python регулярные выражения группы: Регулярные выражения в Python от простого к сложному. Подробности, примеры, картинки, упражнения / Хабр
Регулярные выражения в Python: теория и практика
Рассмотрим регулярные выражения в Python, начиная синтаксисом и заканчивая примерами использования.
Примечание Вы читаете улучшенную версию некогда выпущенной нами статьи.
- Для чего нужны регулярные выражения?
- Регулярные выражения в Python
- Задачи
Для чего нужны регулярные выражения?
- для определения нужного формата, например телефонного номера или email-адреса;
- для разбивки строк на подстроки;
- для поиска, замены и извлечения символов;
- для быстрого выполнения нетривиальных операций.
Синтаксис таких выражений в основном стандартизирован, так что вам следует понять их лишь раз, чтобы использовать в любом языке программирования.
Примечание Не стоит забывать, что регулярные выражения не всегда оптимальны, и для простых операций часто достаточно встроенных в Python функций.
Хотите узнать больше? Обратите внимание на статью о регулярках для новичков.
Регулярные выражения в Python
В Python для работы с регулярками есть модуль re
. Его нужно просто импортировать:
import re
А вот наиболее популярные методы, которые предоставляет модуль:
re.match()
re.search()
re.findall()
re.split()
re.sub()
re.compile()
Рассмотрим каждый из них подробнее.
re.match(pattern, string)
Этот метод ищет по заданному шаблону в начале строки. Например, если мы вызовем метод match()
на строке «AV Analytics AV» с шаблоном «AV», то он завершится успешно. Но если мы будем искать «Analytics», то результат будет отрицательный:
import re
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
<_sre.SRE_Match object at 0x0000000009BE4370>
Искомая подстрока найдена. Чтобы вывести её содержимое, применим метод group()
(мы используем «r» перед строкой шаблона, чтобы показать, что это «сырая» строка в Python):
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
AV
Теперь попробуем найти «Analytics» в данной строке. Поскольку строка начинается на «AV», метод вернет None
:
result = re.match(r'Analytics', 'AV Analytics Vidhya AV')
print result
Результат:
None
Также есть методы start()
и end()
для того, чтобы узнать начальную и конечную позицию найденной строки.
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.start()
print result.end()
Результат:
0
2
Эти методы иногда очень полезны для работы со строками.
re.search(pattern, string)
Метод похож на match()
, но ищет не только в начале строки. В отличие от предыдущего, search()
вернёт объект, если мы попытаемся найти «Analytics»:
result = re.search(r'Analytics', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
Analytics
Метод search()
ищет по всей строке, но возвращает только первое найденное совпадение.
re.findall(pattern, string)
Возвращает список всех найденных совпадений. У метода findall()
нет ограничений на поиск в начале или конце строки. Если мы будем искать «AV» в нашей строке, он вернет все вхождения «AV». Для поиска рекомендуется использовать именно findall()
, так как он может работать и как re.search()
, и как re.match()
.
result = re.findall(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
['AV', 'AV']
re.split(pattern, string, [maxsplit=0])
Этот метод разделяет строку по заданному шаблону.
result = re. split(r'y', 'Analytics')
print result
Результат:
['Anal', 'tics']
В примере мы разделили слово «Analytics» по букве «y». Метод split()
принимает также аргумент maxsplit
со значением по умолчанию, равным 0. В данном случае он разделит строку столько раз, сколько возможно, но если указать этот аргумент, то разделение будет произведено не более указанного количества раз. Давайте посмотрим на примеры:
result = re.split(r'i', 'Analytics Vidhya')
print result
Результат:
['Analyt', 'cs V', 'dhya'] # все возможные участки.
result = re.split(r'i', 'Analytics Vidhya',maxsplit=1)
print result
Результат:
['Analyt', 'cs Vidhya']
Мы установили параметр maxsplit
равным 1, и в результате строка была разделена на две части вместо трех.
re.sub(pattern, repl, string)
Ищет шаблон в строке и заменяет его на указанную подстроку. Если шаблон не найден, строка остается неизменной.
result = re.sub(r'India', 'the World', 'AV is largest Analytics community of India')
print result
Результат:
'AV is largest Analytics community of the World'
re.compile(pattern, repl, string)
Мы можем собрать регулярное выражение в отдельный объект, который может быть использован для поиска. Это также избавляет от переписывания одного и того же выражения.
pattern = re.compile('AV')
result = pattern.findall('AV Analytics Vidhya AV')
print result
result2 = pattern.findall('AV is largest analytics community of India')
print result2
Результат:
['AV', 'AV']
['AV']
До сих пор мы рассматривали поиск определенной последовательности символов. Но что, если у нас нет определенного шаблона, и нам надо вернуть набор символов из строки, отвечающий определенным правилам? Такая задача часто стоит при извлечении информации из строк. и $
Больше информации по специальным символам можно найти в документации для регулярных выражений в Python 3.
Ну хватит теории. Рассмотрим примеры использования Python RegEx.
Задачи
Вернуть первое слово из строки
Сначала попробуем вытащить каждый символ (используя .
)
result = re.findall(r'.', 'AV is largest Analytics community of India')
print result
Результат:
['A', 'V', ' ', 'i', 's', ' ', 'l', 'a', 'r', 'g', 'e', 's', 't', ' ', 'A', 'n', 'a', 'l', 'y', 't', 'i', 'c', 's', ' ', 'c', 'o', 'm', 'm', 'u', 'n', 'i', 't', 'y', ' ', 'o', 'f', ' ', 'I', 'n', 'd', 'i', 'a']
Для того, чтобы в конечный результат не попал пробел, используем вместо .
\w
.
result = re.findall(r'\w', 'AV is largest Analytics community of India')
print result
Результат:
['A', 'V', 'i', 's', 'l', 'a', 'r', 'g', 'e', 's', 't', 'A', 'n', 'a', 'l', 'y', 't', 'i', 'c', 's', 'c', 'o', 'm', 'm', 'u', 'n', 'i', 't', 'y', 'o', 'f', 'I', 'n', 'd', 'i', 'a']
Теперь попробуем достать каждое слово (используя *
или +
)
result = re.findall(r'\w*', 'AV is largest Analytics community of India')
print result
Результат:
['AV', '', 'is', '', 'largest', '', 'Analytics', '', 'community', '', 'of', '', 'India', '']
И снова в результат попали пробелы, так как *
означает «ноль или более символов». Для того, чтобы их убрать, используем +
:
result = re.findall(r'\w+', 'AV is largest Analytics community of India')
print result
Результат:
['AV', 'is', 'largest', 'Analytics', 'community', 'of', 'India']
Теперь вытащим первое слово, используя ^
:
result = re.
, то мы получим последнее слово, а не первое:result = re.findall(r'\w+$', 'AV is largest Analytics community of India') print result Результат: [‘India’]
Вернуть первые два символа каждого слова
Вариант 1: используя
\w
, вытащить два последовательных символа, кроме пробельных, из каждого слова:result = re.findall(r'\w\w', 'AV is largest Analytics community of India') print result Результат: ['AV', 'is', 'la', 'rg', 'es', 'An', 'al', 'yt', 'ic', 'co', 'mm', 'un', 'it', 'of', 'In', 'di']
Вариант 2: вытащить два последовательных символа, используя символ границы слова (
\b
):result = re.findall(r'\b\w.', 'AV is largest Analytics community of India') print result Результат: ['AV', 'is', 'la', 'An', 'co', 'of', 'In']
Вернуть домены из списка email-адресов
Сначала вернём все символы после «@»:
result = re. findall(r'@\w+', '[email protected], [email protected], [email protected], [email protected]') print result Результат: ['@gmail', '@test', '@analyticsvidhya', '@rest']
Как видим, части «.com», «.in» и т. д. не попали в результат. Изменим наш код:
result = re.findall(r'@\w+.\w+', '[email protected], [email protected], [email protected], [email protected]') print result Результат: ['@gmail.com', '@test.in', '@analyticsvidhya.com', '@rest.biz']
Второй вариант — вытащить только домен верхнего уровня, используя группировку —
( )
:result = re.findall(r'@\w+.(\w+)', '[email protected], [email protected], [email protected], [email protected]') print result Результат: ['com', 'in', 'com', 'biz']
Извлечь дату из строки
Используем
\d
для извлечения цифр.result = re.findall(r'\d{2}-\d{2}-\d{4}', 'Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009') print result Результат: ['12-05-2007', '11-11-2011', '12-01-2009']
Для извлечения только года нам опять помогут скобки:
result = re. findall(r'\d{2}-\d{2}-(\d{4})', 'Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009') print result Результат: ['2007', '2011', '2009']
Извлечь слова, начинающиеся на гласную
Для начала вернем все слова:
result = re.findall(r'\w+', 'AV is largest Analytics community of India') print result Результат: ['AV', 'is', 'largest', 'Analytics', 'community', 'of', 'India']
А теперь — только те, которые начинаются на определенные буквы (используя
[]
):result = re.findall(r'[aeiouAEIOU]\w+', 'AV is largest Analytics community of India') print result Результат: ['AV', 'is', 'argest', 'Analytics', 'ommunity', 'of', 'India']
Выше мы видим обрезанные слова «argest» и «ommunity». Для того, чтобы убрать их, используем
\b
для обозначения границы слова:result = re.findall(r'\b[aeiouAEIOU]\w+', 'AV is largest Analytics community of India') print result Результат: ['AV', 'is', 'Analytics', 'of', 'India']
Также мы можем использовать
^
внутри квадратных скобок для инвертирования группы:result = re. aeiouAEIOU ]\w+', 'AV is largest Analytics community of India') print result Результат: ['largest', 'community']
Проверить формат телефонного номера
Номер должен быть длиной 10 знаков и начинаться с 8 или 9. Есть список телефонных номеров, и нужно проверить их, используя регулярки в Python:
li = ['9999999999', '999999-999', '99999x9999'] for val in li: if re.match(r'[8-9]{1}[0-9]{9}', val) and len(val) == 10: print 'yes' else: print 'no' Результат: yes no no
Разбить строку по нескольким разделителям
Возможное решение:
line = 'asdf fjdk;afed,fjek,asdf,foo' # String has multiple delimiters (";",","," "). result = re.split(r'[;,\s]', line) print result Результат: ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
Также мы можем использовать метод
re.sub()
для замены всех разделителей пробелами:line = 'asdf fjdk;afed,fjek,asdf,foo' result = re. sub(r'[;,\s]',' ', line) print result Результат: asdf fjdk afed fjek asdf foo
Извлечь информацию из html-файла
Допустим, нужно извлечь информацию из html-файла, заключенную между
<td>
и</td>
, кроме первого столбца с номером. Также будем считать, что html-код содержится в строке.Пример содержимого html-файла:
1NoahEmma2LiamOlivia3MasonSophia4JacobIsabella5WilliamAva6EthanMia7MichaelEmily
С помощью регулярных выражений в Python это можно решить так (если поместить содержимое файла в переменную
test_str
):result = re.findall(r'\d([A-Z][A-Za-z]+)([A-Z][A-Za-z]+)', test_str) print result Результат: [('Noah', 'Emma'), ('Liam', 'Olivia'), ('Mason', 'Sophia'), ('Jacob', 'Isabella'), ('William', 'Ava'), ('Ethan', 'Mia'), ('Michael', 'Emily')]
Адаптированный перевод «Beginners Tutorial for Regular Expressions in Python»
Регулярные выражения — Погружение в Python 3
❝ Некоторые люди, во время решения одной проблемы думают: «Я знаю, я буду использовать регулярные выражения». Теперь у них две проблемы… ❞— Jamie Zawinski
Погружение
Каждый новый язык программирования имеет встроенные функции для работы со строками. В Python, строки имеют методы для поиска и замены: index(), find(), split(), count(), replace() и т.д. Но эти методы ограничены для простейших случаев. Например метод index() ищет простую жёстко заданную часть строки и поиск всегда регистрозависимый. Чтобы выполнить регистронезависимый поиск по строке s, вы должны вызвать s.lower() или s.upper() для того чтобы быть уверенным что строка имеет соответствующий регистр для поиска. Методы replace() и split() имеют те же ограничения.
Если ваша задача может быть решена при помощи этих методов, лучше использовать их. Они простые и быстрые, легко читаемые, много может быть сказано о быстром, простом и удобочитаемом коде. Но если вы обнаружите что вы используете большое количество строковых функций с условиями if для обработки специальных случаев, или используете множество последовательных вызовов split() и join() чтобы нарезать на кусочки ваши строки, значит вы нуждаетесь в регулярных выражениях.
Регулярные выражения это мощный и (по большей части) стандартизированный способ для поиска, замены и парсинга текста при помощи комплексных шаблонов. Хотя синтаксис регулярных выражений довольно сложный и выглядит непохожим на нормальный код (прим. пер. «смахивает на perl»), конечный результат часто более удобочитаемый чем набор из последовательных функций для строк. Существует даже способ поместить комментарии внутрь регулярных выражений, таким образом вы можете включить небольшую документацию в регулярное выражение.
Если вы пользовались регулярными выражениями в других языках (таких как Perl, JavaScript, или PHP), синтаксис Python-а будет для вас достаточно привычным. Прочитайте обзор модуля re для того чтобы узнать о доступных функциях и их аргументах. |
⁂
Учебный пример: Адрес Улицы
Эта серия примеров основана на реальных проблемах, которые появились в моей работе несколько лет назад, когда мне пришлось обработать и стандартизировать адреса улиц, экспортированных из устаревшей системы до того, как произвести импорт в новую систему. (Обратите внимание: это не придуманный пример, им всё ещё можно пользоваться). Этот пример показывает как я подошёл к проблеме:
>>> s = '100 NORTH MAIN ROAD'
>>> s.replace('ROAD', 'RD.') ①
'100 NORTH MAIN RD.'
>>> s = '100 NORTH BROAD ROAD'
>>> s.replace('ROAD', 'RD.') ②
'100 NORTH BRD. RD.'
>>> UNIQae610d7ca506639d-nowiki-00000003-QINU ③
'100 NORTH BROAD RD.'
>>> import re ④
>>> re.sub('ROAD$', 'RD.', s) ⑤
'100 NORTH BROAD RD.'
- ① Моя задача стандартизировать адрес улицы, например 'ROAD' всегда выражается сокращением 'RD.'. На первый взгляд мне показалось, что это достаточно просто, и я могу использовать метод replace(). В конце концов, все данные уже в верхнем регистре и несовпадение регистра не составит проблемы. Строка поиска 'ROAD' являлась константой и обманчиво простой пример s.replace() вероятно работает.
- ② Жизнь же, напротив, полна противоречивых примеров, и я быстро обнаружил один из них. Проблема заключалась в том что 'ROAD' появилась в адресе дважды, один раз как 'ROAD', а во второй как часть названия улицы 'BROAD'. Метод replace() обнаруживал 2 вхождения и слепо заменял оба, разрушая таким образом правильный адрес.
- ③ Чтобы решить эту проблему вхождения более одной подстроки 'ROAD', вам необходимо прибегнуть к следующему: искать и заменять 'ROAD' в последних четырёх символах адреса (s[-4:]), оставляя строку отдельно (s[:-4]). Как вы могли заметить, это уже становится громоздким. К примеру, шаблон зависит от длины заменяемой строки. (Если вы заменяли 'STREET' на 'ST.', вам придется использовать s[:-6] и s[-6:].replace(...).) Не хотели бы вы вернуться к этому коду через полгода для отладки? Я не хотел бы.
- ④ Пришло время перейти к регулярным выражениям. В Python все функции, связанные с регулярными выражениями содержится в модуле re.
- ⑤ Взглянем на первый параметр: 'ROAD$'. , означающий «начало строки».) Используя функцию re.sub() вы ищете в строке s регулярное выражение 'ROAD$' и заменяете на 'RD.'. Оно совпадает с 'ROAD' в конце строки s, но не совпадает с 'ROAD', являющимся частью названия 'BROAD', так как оно находится в середине строки s.
Продолжая историю про обработку адресов, я скоро обнаружил, что предыдущий пример совпадения 'ROAD' на конце адреса был недостаточно хорош, так как не все адреса включали в себя определение улицы. Некоторые адреса просто оканчивались названием улицы. Я избегал этого в большинстве случаев, но если название улицы было 'BROAD', тогда регулярное выражение совпадало с 'ROAD' на конце строки 'BROAD', чего я совершенно не хотел.
>>> s = '100 BROAD'
>>> re.sub('ROAD$', 'RD.', s)
'100 BRD.'
>>> re.sub('\\bROAD$', 'RD.', s) ①
'100 BROAD'
>>> re.sub(r'\bROAD$', 'RD.', s) ②
'100 BROAD'
>>> s = '100 BROAD ROAD APT. 3'
>>> re. sub(r'\bROAD$', 'RD.', s) ③
'100 BROAD ROAD APT. 3'
>>> re.sub(r'\bROAD\b', 'RD.', s) ④
'100 BROAD RD. APT 3'
- ① В действительности я хотел совпадения с 'ROAD' когда оно на конце строки и является самостоятельным словом (а не частью большего). Чтобы описать это в регулярном выражении необходимо использовать '\b', что означает «слово должно оказаться прямо тут.» В Python это сложно, так как '\' знак в строке должен быть экранирован. Иногда это называют как «бедствие бэкслэша» и это одна из причин почему регулярные выражения проще в Perl чем в Python. Однако недостаток Perl в том что регулярные выражения смешиваются с другим синтаксисом, если у вас ошибка, достаточно сложно определить где она, в синтаксисе или в регулярном выражении.
- ② Чтобы обойти проблему «бедствие бэкслэша» вы можете использовать то, что называется неформатированная строка (raw string), путём применения префикса строки при помощи символа 'r'. Это скажет Python-у что ничего в этой строке не должно быть экранировано; '\t' это табулятор, но r'\t' это символ бэкслэша '\' , а следом за ним буква 't'. Я рекомендую всегда использовать неформатированную строку, когда вы имеете дело с регулярными выражениями; с другой стороны всё становится достаточно путанным (несмотря на то что наше регулярное выражения уже достаточно запутано).
- ③ *вздох* К неудаче я скоро обнаружил больше причин противоречащих моей логике. В этом случае адрес улицы содержал в себе цельное отдельное слово 'ROAD' и оно не было на конце строки, так как адрес содержал номер квартиры после определения улицы. Так как слово 'ROAD' не находится в конце строки, регулярное выражение re.sub() его пропускало и мы получали на выходе ту же строку что и на входе, а это то чего вы не хотите.
- ④ Чтобы решить эту проблему я удалил символ '$' и добавил ещё один '\b'. Теперь регулярное выражение совпадало с 'ROAD' если оно являлось цельным словом в любой части строки, на конце, в середине и в начале.
⁂
Учебный пример: Римские цифры
Скорее всего вы видели римские цифры, даже если вы в них не разбираетесь. Вы могли видеть их на копирайтах старых фильмов и ТВ-шоу («Copyright MCMXLVI» вместо «Copyright 1946»), или на стенах в библиотеках университетов («учреждено MDCCCLXXXVIII» вместо « учреждено 1888»). Вы могли видеть их в структуре библиографических ссылок. Эта система отображения цифр относится к древней Римской империи (отсюда и название).
В римских цифрах семь символов, которые повторяются в различных комбинациях для отображения цифр.
- I = 1
- V = 5
- X = 10
- L = 50
- C = 100
- D = 500
- M = 1000
Нижеследующие правила позволяют конструировать римские цифры:
- Иногда символы складываются. I это 1, II это 2, и III это 3. VI это 6 (посимвольно, «5 и 1»), VII это 7, и VIII это 8.
- Десятичные символы (I, X, C, и M) могут быть повторены до 3 раз. Для образования 4 вам необходимо отнять от следующего высшего символа пятёрки. Нельзя писать 4 как IIII; вместо этого, она записывается как IV («на 1 меньше 5»). 40 записывается как XL («на 10 меньше 50»), 41 как XLI, 42 как XLII, 43 как XLIII, и 44 как XLIV («на 10 меньше 50, и на 1 меньше 5»).
- Иногда символы… обратны сложению. Разместив определённые символы до других, вы вычитаете их от конечного значения. Например 9, вам необходимо отнять от следующего высшего символа десять: 8 это VIII, но 9 это IX («на 1 меньше 10»), не VIIII (так как символ I не может быть повторён 4 раза). 90 это XC, 900 это CM.
- Пятёрки не могут повторяться. 10 всегда отображается как X, никогда как VV. 100 всегда C, никогда LL.
- Римские цифры читаются слева направо, поэтому положение символа имеет большое значение. DC это 600; CD это совершенно другая цифра (400, «на 100 меньше 500»). CI это 101; IC это даже не является допустимым Римским числом (так как вы не можете вычитать 1 прямо из 100; вам необходимо записать это как XCIX, «на 10 меньше 100, и на 1 меньше 10»). в начале, это означает что патерн должен совпасть с полной строкой, без других символов до и после символов М.
- ② Сущность модуля re это функция search(), которая использует патерн регулярного выражения (pattern) и строку ('M') и ищет совпадения в соответствии регулярному выражению. Если совпадение обнаружено, search() возвращает объект который имеет различные методы описания совпадения; если совпадения не обнаружено, search() возвращает None, в Python значение нуля (null). Всё о чём мы заботимся в данный момент, совпадёт ли патерн, это можно сказать глянув на значение возвращаемое функцией search(). 'M' совпадает с этим регулярным выражением, так как первое опциональное M совпадает, а второе опциональное М и третье игнорируется.
- ③ 'MM' совпадает так как первое и второе опциональное М совпадает а третье игнорируется
- ④ 'MMM' совпадает полностью, так как все три символа М совпадают
- ⑤ 'MMMM' не совпадает. Все три М совпадают, но регулярное выражение настаивает на конце строки, (так как требует символ $), а строка ещё не кончилась (из за четвёртого М). Поэтому search() возвращает None.
- ⑥ Занимательно то, что пустая строка также совпадает с регулярным выражением, так как все символы М опциональны.
Проверка на сотни
? делает патерн необязательным
Расположение сотен более сложное чем тысяч, так как существует несколько взаимно исключающих путей записи и зависит от значения.
- 100 = C
- 200 = CC
- 300 = CCC
- 400 = CD
- 500 = D
- 600 = DC
- 700 = DCC
- 800 = DCCC
- 900 = CM
Таким образом есть четыре возможных патерна:
- CM
- CD
- От ноль до трёх символов C (ноль если месть сотен пусто)
- D, от последующх нулей до трёх символов C
Два последних патерна комбинированные:
- опциональное D, за ним от нуля до трёх символов C
Этот пример показывает как проверить позицию сотни в римском числе. ), потом тысячи (M?M?M?). Следом идёт новая часть в скобках, которая описывает три взаимоисключающих патерна разделённых вертикальной линией: CM, CD и D?C?C?C? (который является опциональным D и следующими за ним от нулей до трёх опциональных символов C). Парсер регулярного выражения проверяет каждый из этих патерновв последовательности от левого к правому, выбирая первый подходящий и игнорируя последующие.
- ② 'MCM' совпадает так как первый M совпадает, второй и третий символ M игнорируется, символы CM совпадают (и CD и D?C?C?C? патерны после этого не анализируются). MCM это римское представление числа 1900.
- ③ 'MD' совпадает так как первый M совпадает, второй и третий символ M игнорируется, и патерн D?C?C?C? Совпадает с D (три символа C опциональны и игнорируются). MD это римское представление числа 1500.
- ④ 'MMMCCC' совпадает так как первый M совпадает, и патерн D?C?C?C? сопадает с CCC (символ D опциональный и игнорируются). MMMCCC i это римское представление числа 3300.
- ⑤ 'MCMC' не совпадает. Первый символ M совпадает, второй и третий символ M игнорируется, также совпадает CM, но патерн $ не совпадает так как вы ещё не в конце строки (вы ещё имеете не совпадающий символ C). Символ C не совпадает как часть патерна D?C?C?C?, так как исключающий патерн CM уже совпал.
- ⑥ Занимательно то, что пустая строка всё ещё совпадает с регулярным выражением, так как все символы М опциональны и игнорируются и пустая строка совпадает с патерном D?C?C?C? где все символы опциональны и игнорируются.
Опаньки! Вы заметили как быстро регулярные выражения становятся отвратительными? И пока что мы обработали только позиции тысяч и сотен в римском представлении чисел. Но если последуете далее, вы обнаружите что десятки и единицы описать будет легче, так как они имеют такой же патерн. Тем временем давайте рассмотрим другой путь описать этот патерн.
⁂
Использование синтаксиса {n, m}
модификатор {1,4} совпадает с 1 до 4 вхождением патерна
В предыдущей секции мы имели дело с патерном где одинаковый символ может повториться до трёх раз. M{0,3}$' ①
>>> re.search(pattern, 'M') ②
UNIQae610d7ca506639d-nowiki-00000049-QINU
>>> re.search(pattern, 'MM') ③
<_sre.SRE_Match object at 0x008EE090>
>>> re.search(pattern, 'MMM') ④
<_sre.SRE_Match object at 0x008EEDA8>
>>> re.search(pattern, 'MMMM') ⑤
>>>
- ① Этот патерн говорит: «Совпасть с началом строки, потом с от нуля до трёх символов М находящимися где угодно, потом с концом строки». Символы 0 и 3 могут быть любыми цифрами, если вам необходимо совпадение с 1 и более символами М, необходимо записать М{1,3}.
- ② Тут патерн совпадает с началом строки, потом с одним из возможных трёх символов М, потом с концом строки.
- ③ Тут патерн совпадает с началом строки, потом с двумя из возможных трёх символов М, потом с концом строки.
- ④ Тут патерн совпадает с началом строки, потом с тремя из возможных трёх символов М, потом с концом строки. M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)$'
>>> re.search(pattern, 'MCMXL') ①
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCML') ②
<_sre.SRE_Match object at 0x008EEB48>
>>> re.search(pattern, 'MCMLX') ③
UNIQae610d7ca506639d-nowiki-0000004F-QINU
>>> re.search(pattern, 'MCMLXXX') ④
UNIQae610d7ca506639d-nowiki-00000050-QINU
>>> re.search(pattern, 'MCMLXXXX') ⑤
>>>- ① Тут патерн совпадает с началом строки, потом с первым опциональным символом М, потом CM, потом XL, потом с концом строки. Вспомните что синтаксис (A|B|C) означает «совпасть только с одним оз символов A, B или C» У нас совпадает XL, и мы игнорируем XC и L?X?X?X?, а после этого переходим к концу строки. MCMXL это римское представление числа 1940.
- ② Тут патерн совпадает с началом строки, потом с первым опциональным символом М, потом CM, потом с L?X?X?X?. Из L?X?X?X? Совпадает L и пропускает три опциональных символа X. После этого переходит к концу строки. MCML это римское представление числа 1950.
- ③ Тут патерн совпадает с началом строки, потом с первым опциональным символом М, потом CM, потом с опциональным L и первым опциональным X, пропуская второй и третий опциональные символы X, после этого переходит к концу строки. MCMLX это римское представление числа 1960.
- ④ Тут патерн совпадает с началом строки, потом с первым опциональным символом М, потом CM, потом с опциональным L и всеми тремя опциональными символами X, после этого переходит к концу строки. MCMLXXX это римское представление числа 1980.
- ⑤ Тут патерн совпадает с началом строки, потом с первым опциональным символом М, потом CM, потом с опциональным L и всеми тремя опциональными символами X, после этого не совпадает с концом строки, так как есть ещё один символ X, таким образом патерн не срабатывает и возвращает None. MCMLXXXX это недопустимое римское число.
(A|B) совпадает либо с A либо с B. M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
>>> re.search(pattern, 'MDLV') ①
UNIQae610d7ca506639d-nowiki-00000053-QINU
>>> re.search(pattern, 'MMDCLXVI') ②
UNIQae610d7ca506639d-nowiki-00000054-QINU
>>> re.search(pattern, 'MMMDCCCLXXXVIII') ③
UNIQae610d7ca506639d-nowiki-00000055-QINU
>>> re.search(pattern, 'I') ④
UNIQae610d7ca506639d-nowiki-00000056-QINU- ① Тут патерн совпадает с началом строки, потом с одним из трёх возможных символов М, потом D?C{0,3}. Из них совпадает только опциональное D и ни один из опциональных C. Далее совпадает опциональное L из L?X{0,3} и ни один из трёх опциональных X. После совпадает с V из V?I{0,3} и ни с одним из трёх опциональных I и наконец с концом строки. MDLV это римское представление числа 1555.
- ② Тут патерн совпадает с началом строки, потом с двумя из трёх возможных символов М, потом D и один опциональный C из D?C{0,3}. Потом L?X{0,3} с L и один из трёх возможных X, потом V?I{0,3} с V и одним из трёх I, потом с концом строки. MMDCLXVI это римское представление числа 2666.
- ③ Тут патерн совпадает с началом строки, потом с тремя из трёх M, потом D и C из D?C{0,3}, потом L?X{0,3} с L и три из трёх X, потом V?I{0,3} с V и тремя из трёх I, потом конец строки. MMMDCCCLXXXVIII это римское представление числа 3888, и это максимально длинное римское число которое можно записать без расширенного синтаксиса.
- ④ Смотрите внимательно. (Я чувствую себя магом, «Смотрите внимательно детки, сейчас кролик вылезет из моей шляпы ;)» Тут совпадает начало строки, ни один из трёх М, потом D?C{0,3} пропускает опциональный D и три опциональных C, потом L?X{0,3} пропуская опциональный L и три опциональных X,потом V?I{0,3} пропуская опциональный V и один из трёх опциональных I. Потом конец строки. Стоп, фуф.
Если вы следовали всему и поняли с первой попытки, значит у вас получается лучше чем у меня. Теперь представьте что вы пытаетесь разобраться в чьих то регулярных выражениях в важной функции в рамках огромной программы. Или например представьте что вы возвращаетесь к собственной программе через несколько месяцев. Я делал это и это не слишком приятное зрелище.
А сейчас давайте исследуем альтернативный синтаксис, который позволит легче выполнять поддержку ваших выражений.
⁂
Подробные регулярные выражения
До сих пор вы имели дело с тем что я называю «компактными» регулярными выражениями. Как вы могли заметить они трудны для прочтения, даже если вы понимаете что они делают. Нет гарантии что вы сможете разобраться в них спустя шесть месяцев. Что вам действительно необходимо так это вложенная документация
Python позволяет вам сделать это при помощи подробных регулярных выражений. Подробные регулярные выражения отличаются от компактных двумя способами:
- Пустые строки игнорируются, пробелы, табы и возвраты каретки не совпадают соответственно. Они вообще не совпадают. (Если вы хотите совпадения с пробелом в подробном регулярном выражении, вам необходимо поставить бэкслэш перед ним. # начало строки
M{0,3} # тысячи - 0 до 3 M
(CM|CD|D?C{0,3}) # сотни — 900 (CM), 400 (CD), 0-300 (0 до 3 C),
# или 500-800 (D, с последующими от 0 до 3 C)
(XC|XL|L?X{0,3}) # десятки - 90 (XC), 40 (XL), 0-30 (0 до 3 X),
# или 50-80 (L, с последующими от 0 до 3 X)
(IX|IV|V?I{0,3}) # единицы - 9 (IX), 4 (IV), 0-3 (0 до 3 I),
# или 5-8 (V, с последующими от 0 до 3 I)
$ # конец строки
'''
>>> re.search(pattern, 'M', re.VERBOSE) ①
UNIQae610d7ca506639d-nowiki-00000058-QINU
>>> re.search(pattern, 'MCMLXXXIX', re.VERBOSE) ②
UNIQae610d7ca506639d-nowiki-00000059-QINU
>>> re.search(pattern, 'MMMDCCCLXXXVIII', re.VERBOSE) ③
<_sre.SRE_Match object at 0x008EEB48>
>>> re. search(pattern, 'M') ④- ① Главное что надо запомнить, это то что необходимо добавлять экстра аргументы для работы с ними: re.VERBOSE это константа определённая в модуле re которая служит сигналом что патерн должен быть использован как подробное регулярное выражение. Как вы можете видеть, этот патерн содержит большое количество пустых строк. (и все они игнорируются), а также несколько комментариев (которые игнорируются также). Если мы игнорируем комментарии и пустые строки, то получается то же самое регулярное выражение что и в предыдущем примере, но в гораздо более читабельном виде.
- ② Здесь совпадает начало строки, потом одно и трёх возможных M, потом CM, потом L и три из возможных X, потом IX, потом конец строки.
- ③ Здесь совпадает начало строки, потом три из трёх возможных M, потом D и три из возможных трёх C, потом L и три из трёх возможных X, потом V и три из трёх возможных I, потом конец строки.
- ④ Тут не совпадает. Почему? Так как отсутствует флаг re.VERBOSE и функция re.search рассматривает патерн как компактное регулярное выражение, с значащими пробелами и символами #. Python не может автоматически определить является ли регулярное выражение подробным или нет. Python рассматривает каждое регулярное выражение как компактное до тех пор пока вы не укажете что оно подробное.
⁂
Учебный пример: Обработка телефонных номеров
\d совпадает с любыми цифрами (0–9). \D совпадает со всем кроме цифр
До сих пор вы были сконцентрированы на полных патернах. Совпадает патерн или не совпадает, но регулярные выражения могут быть гораздо мощнее этого. Когда регулярное выражение совпадает с чем либо, вы можете получить специально выделенную часть совпадения. Вы можете узнать что совпало и где.
Этот пример появился из ещё одной реальной проблемы которые я испытывал на предыдущей работе. Проблема была в обработке американских телефонных номеров. Клиент хочет ввести телефонный номер в простое поле (без разделителей), но потом также хочет сохранить индекс, магистраль, номер и опционально добавочную информацию в базе данных компании. (\d{3})-(\d{3})-(\d{4})$') ①
>>> phonePattern.search('800-555-1212').groups() ②
('800', '555', '1212')
>>> phonePattern.search('800-555-1212-1234') ③
>>> phonePattern.search('800-555-1212-1234').groups() ④
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'- ① Всегда читайте регулярное выражение слева направо. Выражение совпадает с началом строки и потом с (\d{3}). Что такое \d{3}? Итак , \d значит «любая цифра» (от 0 до 9). {3} значит «совпадение с конкретно тремя цифрами»; это вариации на тему {n, m} синтаксиса который вы наблюдали ранее. Если заключить это выражение в круглые скобки, то это значит «совпасть должно точно три цифры и потом запомнить их как группу которую я запрошу позже». Потом выражение должно совпасть с дефисом. Потом совпасть с другой группой из трёх цифр, потм опять дефис. Потом ещё одна группа из четырёх цифр. И в конце совпадение с концом строки.
- ② Чтобы получить доступ к группам которые запомнил обработчик регулярного выражения, используйте метод groups() на объекте который возвращает метод search(). Он должен вернуть кортеж такого количества групп, которое было определено в регулярном выражении. В нашем случае определены три группы, одна с тремя цифрами, другая с тремя цифрами и третья с четырьмя цифрами.
- ③ Это регулярное выражение не окончательный ответ, так как оно не обрабатывает расширение после телефонного номера. Для этого вы должны расширить регулярное выражение.
- ④ Вот почему вы не должны использовать «цепочку» из методов search() и groups() в продакшн коде. Если метод search() не вернёт совпадения, то он вернёт None, это не стандартный объект регулярного выражения. Вызов None.groups() генерирует очевидное исключение: None не имеет метода groups(). (Конечно же это немного менее очевидно, когда вы получаете это исключение из глубин вашего кода. (\d{3})-(\d{3})-(\d{4})-(\d+)$') ①
>>> phonePattern.search('800-555-1212-1234').groups() ②
('800', '555', '1212', '1234')
>>> phonePattern.search('800 555 1212 1234') ③
>>>
>>> phonePattern.search('800-555-1212') ④
>>>- ① Это регулярное выражение почти идентично предыдущему. Так же как и до этого оно совпадает с началом строки, потом с запомненной группой из трёх цифр, потом дефис, потом запомненная группа из трёх цифр, потом дефис, потом запомненная группа из четырёх цифр. Что же нового? Это совпадение с другим дефисом и запоминаемая группа из одной и более цифры.
- ② Метод groups() теперь возвращает кортеж из четырёх элементов, а регулярное выражение теперь запоминает четыре группы.
- ③ К неудаче это регулярное выражение не является финальным ответом, так как оно подразумевает что различные части номера разделены дефисом. (\d{3})\D+(\d{3})\D+(\d{4})\D+(\d+)$') ①
>>> phonePattern.search('800 555 1212 1234').groups() ②
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212-1234').groups() ③
('800', '555', '1212', '1234')
>>> phonePattern.search('80055512121234') ④
>>>
>>> phonePattern.search('800-555-1212') ⑤
>>>- ① Держите свою шляпу. У вас совпадает начало строки, потом группа из трёх цифр, потом \D+. Что это за чертовщина? Ок, \D совпадает с любым символом кроме цифр и также «+» означает «1 или более». Итак \D+ означает один или более символом не являющихся цифрами. Это то что вы используете вместо символа дефиса «-» чтобы совпадало с любыми разделителями.
- ② Использование \D+ вместо «-» значит, что теперь регулярное выражение совпадает с телефонным номером разделённым пробелами вместо дефисов.
- ③ Конечно телефонные номера разделенные дефисами тоже срабатывают. (\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') ①
>>> phonePattern.search('80055512121234').groups() ②
('800', '555', '1212', '1234')
>>> phonePattern.search('800.555.1212 x1234').groups() ③
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups() ④
('800', '555', '1212', '')
>>> phonePattern.search('(800)5551212 x1234') ⑤
>>>- ① Только одно изменение, замена «+» на «*». Вместо \D+ между частями номера, теперь используется \D*. Помните что «+» означает «1 или более»? Ок, «*» означает «ноль или более». Итак теперь вы можете обработать номер даже если он не содержит разделителей.
- ② Подумать только, это действительно работает. Почему? У вас совпадает начало строки, потом запоминается группа из трёх цифр (800), потом ноль или более нецифровых символов, потом запоминается группа из трёх цифр (555), потом ноль или более нецифровых символов, потом запоминается группа из четырёх цифр (1212), потом ноль или более нецифровых символов, потом запоминается группа из произвольного количества цифр (1234), потом конец строки. \D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') ①
>>> phonePattern.search('(800)5551212 ext. 1234').groups() ②
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212').groups() ③
('800', '555', '1212', '')
>>> phonePattern.search('work 1-(800) 555.1212 #1234') ④
>>>- ① Это то же самое что и в предыдущем примере, кроме \D*, ноль или более нецифровых символов, до первой запомненной группы (код города). Заметьте что вы не запоминаете те нецифровые символы до кода города (они не в скобках). Если вы обнаружите их, вы просто пропустите их и запомните код города.
- ② Вы можете успешно обработать телефонный номер, даже со скобками до кода города. (Правая скобка также обрабатывается; как нецифровой символ и совпадает с \D* после первой запоминаемой группы.)
- ③ Простая проверка не поломали ли мы чего-то, что должно было работать. Так как лидирующие символы полностью опциональны, совпадает начало строки, ноль нецифровых символов, потом запоминается группа из трёх цифр (800), потом один нецифровой символ (дефис), потом группа из трёх цифр (555), потом один нецифровой (дефис), потом запоминается группа из четырёх цифр (1212), потом ноль нецифровых символов, потом группа цифр из нуля символов, потом конец строки.
- ④ Вот где регулярное выражение выколупывает мне глаза тупым предметом. Почему этот номер не совпал? Потому что 1 находится до кода города, но вы допускали что все лидирующие символы до кода города не цифры (\D*).
Давайте вернёмся назад на секунду. До сих пор регулярное выражение совпадало с началом строки. Но сейчас вы видите что в начале могут быть непредсказуемые символы которые мы хотели бы проигнорировать. Лучше не пытаться подобрать совпадение для них, а просто пропустить их все, давайте сделаем другое допущение: не пытаться совпадать с началом строки вообще. Этот подход показан в следующем примере.
>>> phonePattern = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') ①
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() ②
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212') ③
('800', '555', '1212', '')
>>> phonePattern.search('80055512121234') ④
('800', '555', '1212', '1234')- ① Заметьте отсутствие
^
в регулярном выражении. Вы больше не совпадаете с началом строки. Ничего теперь не подсказывает как следует поступать с введёнными данными вашему регулярному выражению. Обработчик регулярного выражения будет выполнять тяжелую работу чтобы разобраться где же введённая строка начнёт совпадать. - ② Теперь вы можете успешно обработать телефонный номер который включает лидирующие символы и цифры, плюс разделители любого типа между частями номера.
- ③ Простая проверка. Всё работает.
- ④ И даже это работает тоже.
Видите как быстро регулярное выражение выходит из под контроля? Бросим взгляд на предыдущие итерации. Можете ли вы объяснить разницу между одним и другим?
Пока вы понимаете финальный ответ (а это действительно он; если вы обнаружили ситуацию которую он не обрабатывает, я не желаю об этом знать), напишем подробное регулярное выражение, до тех пор пока вы не забыли почему вы сделали выбор который вы сделали.
>>> phonePattern = re.compile(r'''
# don't match beginning of string, number can start anywhere
(\d{3}) # area code is 3 digits (e. g. '800')
\D* # optional separator is any number of non-digits
(\d{3}) # trunk is 3 digits (e.g. '555')
\D* # optional separator
(\d{4}) # rest of number is 4 digits (e.g. '1212')
\D* # optional separator
(\d*) # extension is optional and can be any number of digits
$ # end of string
''', re.VERBOSE)
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() ①
('800', '555', '1212', '1234')
>>> phonePattern.search('800-555-1212') ②
('800', '555', '1212', '')- ① Кроме того что оно разбито на множество строк, это совершенно такое же регулярное выражение как было в последнем шаге, и не будет сюрпризом что оно обрабатывает такие же входные данные.
- ② Финальная простая проверка. Да, всё ещё работает. Вы сделали это.
Итоги
Это всего лишь верхушка айсберга того что могут делать регулярные выражения. совпадение с началом строки.
$ совпадение с концом строки.
\b совпадает с границей слова.
\d совпадает с цифрой.
\D совпадает с не цифрой.
x? совпадает с опциональным символом x (другими словами ноль или один символов x).
x* совпадает с ноль или более x.
x+ совпадает с один или более x.
x{n, m} совпадает с x не менее n раз, но не более m раз.
(a|b|c) совпадает с a или b или c.
(x) группа для запоминания. Вы можете получить значение используя метод groups() на объекте который возвращает re.search.Регулярные выражения экстремально мощный инструмент, но они не всегда корректный способ для решения любой проблемы. Вы должны изучить побольше о них чтобы разобраться когда они являются подходящими для решения проблемы, так как иногда они могут добавить больше проблем чем решить
Группировка регулярных выражений с несколькими совпадениями Ru Python
Быстрый вопрос регулярного выражения.
Я пытаюсь захватить несколько экземпляров группы захвата в python (не думаю, что это специфичный для python), но последующие захваты, похоже, перезаписывают предыдущие.В этом упрощенном примере я по существу пытаюсь разбить строку:
x = 'abcdef' r = re.compile ('(\ w) {6}') m = r.match (x) m.groups () # = ('f',)?!?
Я хочу получить
('a', 'b', 'c', 'd', 'e', 'f')
, но поскольку regex перезаписывает последующие захваты, я получаю('f',)
Является ли это так, как должно выглядеть регулярное выражение? Есть ли способ сделать то, что я хочу, не повторяя синтаксис шесть раз?
Заранее спасибо!
АндрейБоюсь, вы не можете использовать группы для этого. Каждая группа может соответствовать только один раз, я считаю, что все регулярные выражения работают таким образом. Возможное решение – попытаться использовать findall () или аналогичный.
r=re.compile(r'\w') r.findall(x) # 'a', 'b', 'c', 'd', 'e', 'f'
Модуль regex может это сделать.
> m = regex.match('(\w){6}', "abcdef") > m.captures(1) ['a', 'b', 'c', 'd', 'e', 'f']
Также работает с именованными записями:
> m = regex.match('(?P<letter>)\w)', "abcdef") > m.capturesdict() {'letter': ['a', 'b', 'c', 'd', 'e', 'f']}
Ожидается, что модуль regex заменит модуль «re» – это замещающая замена, которая действует одинаково, за исключением того, что она имеет гораздо больше функций и возможностей.
Чтобы найти все совпадения в заданной строке, используйте re.findall (regex, string) . Кроме того, если вы хотите получить каждую букву здесь, ваше регулярное выражение должно быть
'(\w){1}'
или просто'(\w)'
.Видеть:
r = re.compile('(\w)') l = re.findall(r, x) l == ['a', 'b', 'c', 'd', 'e', 'f']
Полагаю, ваш вопрос – это упрощенная презентация ваших потребностей.
Затем я немного причудлива:
import re pat = re. compile('[UI][bd][ae]') ch = 'UbaUdeIbaIbeIdaIdeUdeUdaUdeUbeIda' print [mat.group() for mat in pat.finditer(ch)]
результат
['Uba', 'Ude', 'Iba', 'Ibe', 'Ida', 'Ide', 'Ude', 'Uda', 'Ude', 'Ube', 'Ida']
16 — Замены с помощью регулярных выражений
Содержание
- Замены - функция
re.sub(pattern, repl, string)
- Именованные группы
Замены в регурярных выражениях
В стандартных строках Python есть функция
.replace(old, new)
, которую можно успешно использовать для замены одной строки на другую:>>> string = 'Алёна мыла ёлку!' >>> print(string.replace('ё', 'е')) Алена мыла елку!
Но, что, делать в более сложных случаях? Ну не писать же несколько раз вызов функции
.replace()
с разными аргументами>>> string = 'Ёлку мыла Алёна...' >>> print(string.replace('ё', 'е'). replace('Ё', 'Е')) Елку мыла Алена...
На помощь приходят регулярные выражения и модуль
re
со своей функциейre.sub()
.Сигнатура методы такая:
re.sub(pattern, repl, string)
, где- pattern - это регулярное выражение - шаблон для поиска строки, которую нужно заменить
- repl - строка, на которую нужно произвести замену
- string - сама строка, над которой нужно произвести манипуляции
Метод
re.sub()
ищет шаблонpattern
в строкеstring
и заменяет его наrepl
.
Метод возвращает новую строку. Если шаблон не найден в строке, то текст возвращается без изменений.>>> # Задача: заменить все числа на слово NUM >>> # >>> import re >>> string = 'Мой дядя родился в 48 году и в 2000 ему было 52' >>> pattern = '[0-9]+' >>> print(re. sub(pattern, 'NUM', string)) Мой дядя родился в NUM году и в NUM ему было NUM
Пример с Алёной и заглавной и строчной буквой ё нельзя запрограммировать одной регуляркой. Подумайте, как можно сделать такую функцию, используя регулярки.
Использование групп при заменах
Представьте, что вам нужно написать функцию, которая будет менять американский формат записи даты
MM/DD/YYYY
на русскийDD.MM.YYYY
. Сейчас не будем говорить, про то, что дни могут быть только в диапазоне от 1 до 31, а месяцы от 1 до 12.Функция может иметь слудующий вид:
def convert_dates(text): pattern = '([0-9]{2})/([0-9]{2})/([0-9]{4})' result = re.search(pattern, text) if result: mm = result.group(1) dd = result.group(2) yyyy = result.group(3) new_date = dd + '/' + mm + '/' + yyyy start, stop = result.span() text = text[:start] + new_date + text[stop:] return text
И работать так:
>>> convert_dates('Я влюбился в тебя 03/21/2017. ') 'Я влюбился в тебя 21/03/2017.'
Но, что если, дат в тексте будет больше, чем одна. Да и вообще, неужели нужно писать столь сложный код для такой логики?
На помощь приходят группы. Функцию выше можно переписать так:
def convert_dates(text): pattern = '([0-9]{2})/([0-9]{2})/([0-9]{4})' repl = r'\2/\1/\3' return re.sub(pattern, repl, text)
А использовать так же:
>>> convert_dates('Я влюбился в тебя 03/21/2017. Мои родители познакомились 03/21/1999') 'Я влюбился в тебя 21/03/2017. Мои родители познакомились 21/03/1999'
Здесь
repl
- это еще один шаблон, который говорит функцииre.sub()
куда вставить ту или иную группы из шаблонаpattern
. Выглядит конечно страшно, но куда деваться.Как, наверное, можно догадаться,
\N
- это указание на конкретную группу из шаблонаpattern
, которую нужно подставить.N
- это номер группы.Именованные группы
Когда количество групп в шаблонах увеличивается, то становится трудно с ними работать. Можно легко запутаться в индексах и допустить ошибку. Здесь на помощь приходят именованные группы, с помощью которых можно дать каждой группе своё имя. Осталось только привыкнуть к синтаксису.
Что, если, в наш пример с датой добавится еще и время…
def convert_dates(text): pattern = '(?P<m>[0-9]{2})/(?P<d>[0-9]{2})/(?P<y>[0-9]{4}) (?P<hm>[0-9]{2}:[0-9]{2})' repl = r'\g<d>/\g<m>/\g<y> в \g<hm>' return re.sub(pattern, repl, text)
>>> convert_dates('Я влюбился в тебя 03/21/2017 23:45 по московскому времени') 'Я влюбился в тебя 21/03/2017 в 23:45 по московскому времени'
(?P<m>[0-9]{2})
-?P<m>
- специальный синтаксис задания имени группы. Имя здесь только то, что заключено в скобки.Обращение к группе происходит тоже с помощью спецального синтаксиса:
\g<d>
Имена групп можно использовать в методе
. group()
def get_mail_provider(email): pattern = '(?P<login>[a-zA-Z0-9_]+)@(?P<provider>(?P<name>[a-zA-Z0-9_]+)\.(?P<domain>[a-zA-Z]+))' result = re.search(pattern, email) if result: return result.group('provider') return None
>>> get_mail_provider('[email protected]') 'yandex.ru'
TBD
Python регулярных выражений
Регулярные выражения представляют собой особую последовательность символов, он может помочь вам легко проверить, соответствует ли строка шаблону.
Python повторно модуль увеличивается, начиная с версии 1.5, регулярного выражения, которое обеспечивает Perl-стиль.
Модуль позволяет повторно языка Python имеет все функции регулярных выражений.
компилировать функцию, чтобы сгенерировать объект регулярного выражения из строки шаблона и дополнительных флагов параметров. Этот объект имеет набор методов для регулярных выражений и подстановки.
Re модуль также обеспечивает способ в соответствии с этими функциями При работе функций узора строку в качестве первого аргумента.
В этом разделе представлены общие функции обработки регулярное выражение Python.
re.match функция
re.match пытается сопоставить шаблон из исходного положения строки, если не согласующий стартовая позиция является успешным, матч () не возвращает ничего.
Синтаксис функции:
re.match(pattern, string, flags=0)
Параметры функции:
параметры описание шаблон Матч регулярное выражение строка Строка для соответствия. флаги Флаг, регулярное выражение соответствия используется для управления, например: соответствует ли чувствительны к регистру, многострочный, и так далее. Успешный метод матча re.match возвращает объект соответствия, в противном случае None.
Мы можем использовать эту группу (NUM) или группы () функцию, чтобы получить объекты, соответствующие выражения совпадают.
Соответствующие методы объекта описание группа (Num = 0) Весь соответствующий строковое выражение, группа () может ввести более одного номера группы, в этом случае он будет возвращать значение, соответствующее этим группам кортежей. группы () Он возвращает кортеж из всех групп строки, от 1 до количества, содержащегося в группе. Пример 1:
#!/usr/bin/python # -*- coding: UTF-8 -*- import re print(re.match('www', 'www.w3big.com').span()) # 在起始位置匹配 print(re.match('com', 'www.w3big.com')) # 不在起始位置匹配
Запуск в приведенном выше примере выход:
(0, 3) None
Пример 2:
#!/usr/bin/python import re line = "Cats are smarter than dogs" matchObj = re. match( r'(.*) are (.*?) .*', line, re.M|re.I) if matchObj: print "matchObj.group() : ", matchObj.group() print "matchObj.group(1) : ", matchObj.group(1) print "matchObj.group(2) : ", matchObj.group(2) else: print "No match!!"
Результаты приведенных выше примерах, являются следующими:
matchObj.group() : Cats are smarter than dogs matchObj.group(1) : Cats matchObj.group(2) : smarter
re.search метод
re.search сканировать всю строку и возвращает первый успешный матч.
Синтаксис функции:
re.search(pattern, string, flags=0)
Параметры функции:
параметры описание шаблон Матч регулярное выражение строка Строка для соответствия. флаги Флаг, регулярное выражение соответствия используется для управления, например: соответствует ли чувствительны к регистру, многострочный, и так далее. Успешный метод матча re.search возвращает объект соответствия, в противном случае None.
Мы можем использовать эту группу (NUM) или группы () функцию, чтобы получить объекты, соответствующие выражения совпадают.
Соответствующие методы объекта описание группа (Num = 0) Весь соответствующий строковое выражение, группа () может ввести более одного номера группы, в этом случае он будет возвращать значение, соответствующее этим группам кортежей. группы () Он возвращает кортеж из всех групп строки, от 1 до количества, содержащегося в группе. Пример 1:
#!/usr/bin/python # -*- coding: UTF-8 -*- import re print(re.search('www', 'www.w3big.com').span()) # 在起始位置匹配 print(re.search('com', 'www.w3big.com').span()) # 不在起始位置匹配
Запуск в приведенном выше примере выход:
(0, 3) (11, 14)
Пример 2:
#!/usr/bin/python import re line = "Cats are smarter than dogs"; searchObj = re. search( r'(.*) are (.*?) .*', line, re.M|re.I) if searchObj: print "searchObj.group() : ", searchObj.group() print "searchObj.group(1) : ", searchObj.group(1) print "searchObj.group(2) : ", searchObj.group(2) else: print "Nothing found!!"
Результаты приведенных выше примерах, являются следующими:
searchObj.group() : Cats are smarter than dogs searchObj.group(1) : Cats searchObj.group(2) : smarter
Разность re.match и re.search
re.match соответствует только начало строки, если начало строки не соответствует регулярному выражению, совпадение не найдено, функция возвращает None, и re.search совпадают со строкой, пока не найдет совпадения.
Пример:
#!/usr/bin/python import re line = "Cats are smarter than dogs"; matchObj = re.match( r'dogs', line, re.M|re.I) if matchObj: print "match --> matchObj.group() : ", matchObj.group() else: print "No match!!" matchObj = re. search( r'dogs', line, re.M|re.I) if matchObj: print "search --> matchObj.group() : ", matchObj.group() else: print "No match!!"
Примеры приведенных выше результатов заключаются в следующем:
No match!! search --> matchObj.group() : dogs
Поиск и замена
Модуль повторного Python предоставляет re.sub на матч замены строки.
Синтаксис:
re.sub(pattern, repl, string, max=0)
Возвращаемая строка это строка с крайней левой RE матчей не будет повторяться, чтобы заменить. Если шаблон не найден, то символы будут возвращены без изменений.
Необязательный счетчик параметр является максимальное количество раз замену соответствующий шаблон, счетчик должен быть неотрицательным целым числом. Значение по умолчанию 0 означает, что для замены всех вхождений.
Пример:
#!/usr/bin/python import re phone = "2004-959-559 # This is Phone Number" # Delete Python-style comments num = re. и $
re.S Итак, в том числе переводы строк соответствовать всем символам re.U Согласно решения Unicode набор символов символов. Этот флаг влияет \ ш, \ W, \ Ь, \ B. re.X Этот флаг, давая вам более гибкий формат, так что вы будете писать регулярные выражения проще для понимания. Шаблон регулярного выражения
Строка шаблона, используя специальный синтаксис для обозначения регулярное выражение:
Буквы и цифры сами. Регулярное выражение при букв и цифр совпадают ту же строку.
Большинство из букв и цифр будет иметь различное значение, когда ему предшествует обратный слэш.
Пунктуация спасшемся только тогда, когда сам матч, или они представляют собой особый смысл.
Сам Backslash должен использовать побег символ обратной косой.
Поскольку регулярные выражения обычно содержат символы, так что вам лучше использовать исходную строку, чтобы представлять их. ABC] соответствует в дополнение к а, Ь, с символами.
Re * 0 или более выражениям. Re + Один или более совпадающих выражений. повторно? Матч 0 или 1 по предшествующих регулярных выражений для определения сегментов, не жадный путь Re {п} повторно {п,} Точное соответствие п предыдущего выражения. Re {п, т} Матч п в т раз по предшествующих регулярных выражений для определения сегментов, жадный путь а | б Совпадение или б (Re) Выражение матч G в скобках, также представляет собой группу (? Imx) Регулярное выражение состоит из трех дополнительных флагов: я, м, или х. Она влияет только на область в скобках. (? -imx) Регулярные выражения Закрыть я, м, или х необязательный флаг. Она влияет только на область в скобках. (?: Re) Аналогично (...), но не представляет собой группу, (Imx :? Re) Я использую в круглые скобки, м или х необязательный флаг (-imx :? Re) Не используйте I, M в круглых скобках, или х дополнительный флаг (? # ...) Примечание. (? = Re) Форвард уверен разделитель. Если содержится регулярное выражение, представленное здесь ..., успешно матчи в текущем местоположении, и не иначе. Тем не менее, как только содержала выражение была опробована, согласующий двигатель не продвигается, остальная часть узора даже попробовать разделителем правильно. (?! Re) Нападающий отрицанием разделителем. И, конечно, противоречит разделителем, успешным, когда содержащийся выражение не совпадает с текущей позиции в строке (?> Re) Независимый поиск по шаблону, устраняя откаты. \ W Матч алфавитно-цифровой и нижнее подчеркивание \ W Матч не буквенно-цифровых и подчеркивания \ S Соответствует любой символ пробела, что эквивалентно [\ т \ п \ г \ F]. \ S Соответствует любой непустой символ \ D Соответствует любому количеству, которое эквивалентно [0-9]. \ D Соответствует любому нечисловая \ A Соответствует началу строки \ Z Матч конец строки, если она существует символ новой строки, только до конца строки, чтобы соответствовать новой строки. с \ Z конец строки Match \ G Матч Матч завершен последнюю позицию. \ B Матчи границы слова, то есть, оно относится к месту и пробелы между словами. Например, 'эр \ Ъ' не может сравниться с "никогда" в "эр", но не может сравниться с "глаголом" в "эр". \ B Матч граница слова. 'Er \ B' может соответствовать "глагол" в "эр", но не может сравниться с "никогда" в "эр". \ N, \ т, и тому подобное. Соответствует новой строки. Соответствует символу табуляции. подождите \ 1 ... \ 9 Соответствующие подвыражения п-го пакета. \ 10 Матч первые п пакетов подвыражению, если он после матча. В противном случае, выражение относится к восьмеричный код. Примеры регулярных выражений
Символьные матчи
примеров описание питон Matching "питон". Классы персонажей
примеров описание [Pp] ython Matching "Python" или "Python" руб [вы] Матч "Рубин" или "деревенщина" [AEIOU] Любой из букв в скобках соответствия [0-9] Соответствует любой цифре. Аналогично [0123456789] [Az] Соответствует любому строчных букв [AZ] Соответствует любой верхний регистр [A-Za-z0-9] Матчи любые буквы и цифры [^ AEIOU] В дополнение ко всем, кроме букв символов аеиоу [^ 0-9] Соответствующие символы, кроме цифр Специальные классы символов
примеров описание , Соответствует любому одному символу, кроме "\ п" есть. A-Za-z0-9_]'. Регулярные выражения в Python: практическое применение
Регулярные выражения — хороший инструмент для упорядочивания, поиска либо извлечения текстовых данных. В этой статье мы рассмотрим примеры их использования в Python.
Если говорить простым языком, то регулярное выражение представляет собой последовательность символов, применяемых для поиска и замены текста в файле либо строке. При этом используются 2 типа символов: • спецсимволы. У них есть специальные значения, аналогично *, который обычно означает «любой символ»; • литералы (к примеру: a, b, 1, 2 и т. п.).
В языке программирования Python для работы с регулярными выражениями существует модуль re, который надо сначала импортировать:
На практике регулярные выражения чаще всего применяются для решения следующих задач:
• поиск в строке;
• разбиение строки на подстроки;
• замена части строки.Для решения вышеописанных задач библиотека re предоставляет ряд методов, вот самые популярные из них:
• re.match()
• re.search()
• re.findall()
• re.split()
• re.sub()
• re.compile()Давайте посмотрим, как эти методы работают.
re.match(pattern, string)
Метод осуществляет поиск в начале строки по заданному шаблону. Вызвав match() на строке «AV Analytics AV» с шаблоном «AV», мы получим успешный результат поиска. Но если будем искать «Analytics», результат будет отрицательным. Давайте посмотрим, как метод работает:
import re result = re.match(r'AV', 'AV Analytics Vidhya AV') print result
Итог:
<_sre.SRE_Match object at 0x0000000009BE4370>
Итак, искомая подстрока найдена. Если мы хотим вывести её содержимое, пригодится метод group(). Обратите внимание, что мы применяем «r» перед строкой шаблона, дабы показать, что это «сырая» строка.
result = re.match(r'AV', 'AV Analytics Vidhya AV') print result. group(0)
Итог:
А теперь поищем в данной строке «Analytics». Но, как уже было сказано выше, т. к. строка начинается на «AV», результат будет отрицательный:
result = re.match(r'Analytics', 'AV Analytics Vidhya AV') print result
Итог:
Кроме того, существуют методы start() и end(), позволяющие узнать начальную и конечную позиции найденной строки.
result = re.match(r'AV', 'AV Analytics Vidhya AV') print result.start() print result.end()
Итог:
Данные методы бывают весьма полезны при работе со строками.
re.search(pattern, string)
Этот метод схож с методом match(), однако он осуществляет поиск не только в начале строки. Результат будет положительным, даже если мы захотим найти «Analytics».
result = re.search(r'Analytics', 'AV Analytics Vidhya AV') print result.group(0)
Итог:
Таким образом, search() осуществляет поиск по всей строке, возвращая лишь первое найденное совпадение.
re.findall(pattern, string)
Следующий метод вернёт вам список всех найденных совпадений, то есть у него отсутствуют ограничения в плане начала или конца строки. Если будем искать «AV», вернутся все вхождения «AV»:
result = re.findall(r'AV', 'AV Analytics Vidhya AV') print result
Итог:
re.split(pattern, string, [maxsplit=0])
Следующий метод разделяет строку по заданному шаблону.
result = re.split(r't', 'Analytics') print result
Итог:
В нашем примере мы разделили слово «Analytics» по букве «t». Кроме того, split() принимает аргумент maxsplit, значение которого по умолчанию равно 0. То есть мы сможем разделить строку на указанное количество частей.
Пример 1:
result = re.split(r'i', 'Analytics Vidhya') print result
Результат:
['Analyt', 'cs V', 'dhya'] # все возможные части.
Пример 2:
result = re. split(r'i', 'Analytics Vidhya',maxsplit=1) print result
Итог:
re.sub(pattern, repl, string)
Данный метод осуществляет поиск шаблона в строке, заменяя его на указанную подстроку. При отсутствии шаблона строка не меняется.
result = re.sub(r'India', 'the World', 'AV is largest Analytics community of India') print result
Итог:
'AV is largest Analytics community of the World'
re.compile(pattern, repl, string)
Следующий метод позволяет собирать регулярные выражения в отдельный объект, а потом использовать его для поиска. Такое решение избавляет от переписывания одних и тех же выражений.
pattern = re.compile('AV') result = pattern.findall('AV Analytics Vidhya AV') print result result2 = pattern.findall('AV is largest analytics community of India') print result2
Итог:
Итак, мы рассмотрели поиск определённой последовательности символов. Однако бывает, что у нас нет конкретного шаблона, а нам необходимо вернуть набор символов из строки, которая отвечает некоторым правилам (извлечь нужную информацию из строк). В таких ситуациях нам пригодятся специальные символы:
Дополнительную информацию о спецсимволах можно найти в официальной документации.
По материалам «Beginners Tutorial for Regular Expressions in Python».
Использование регулярных выражений в генетике с Python
Дата публикации Apr 6, 2019
Регулярные выражения в Python
Регулярные выражения (регулярные выражения) в Python могут быть использованы, чтобы помочь нам найти шаблоны в генетике. Мы можем использовать регулярные выражения, когда анализируем данные биологической последовательности, так как очень часто мы ищем паттерны в ДНК, РНК или белках. Эти типы данных последовательности являются просто строками и поэтому замечательно поправимы для анализа паттернов с использованием регулярных выражений Мы можем быть заинтересованы в поиске: нуклеотидных повторов, ответственных за заболевание человека, сайтов связывания фактора транскрипции ДНК, сайтов рестрикции и специфических мутаций. CCC будет соответствовать CCCGGG, но не GGGCCC. Паттерн AAA $ будет соответствовать TTTAAA, но не AAAGGG.
А. точка (или десятичная точка) является подстановочным знаком, который находит любой символ. Если бы протеинкиназа имела консенсусную последовательность X RXYVHXFDEXK ’, где X обозначает любую аминокислоту, тогда регулярное выражение‘ R.YVH.FDE.K ’было бы успешным в поиске субстратов. Однако предупреждение, точка (.) Будет соответствовать любому символу, который даже не является буквой. Поэтому шаблон «R.YVH.FDE.K» будет соответствовать «R8YVH £ FDE & K», что может быть не тем, что мы хотим.
Метасимволы *, +,? И {} являются операторами кванторов. Они используются для указания повторений символа или группы символов. Звездочки, следующие за символом или группой, означают, что этот символ или группа является необязательным, но также может повторяться. Примером в области генетики, где будет использоваться метасимвол звездочек, может быть случай, когда мы ищем чтения RNA-seq, чтобы найти последовательности, которые 3'-полиаденилированы путем поиска AAAAAA * $. Это регулярное выражение найдет ровно 5 A, за которыми следует ноль или более A. Метасимвол + сродни *, за исключением того, что он находит символ один или несколько раз. А? находит предыдущий символ или группу символов ноль или один раз.
Если требуется быть конкретным или соответствовать определенному количеству повторов, мы можем использовать фигурные скобки. Одно число в фигурных скобках будет точно соответствовать количеству повторов в предыдущем символе или группе. Например, CA {3} GATT будет соответствовать CAAAGATT, но не CAAGATT или CAAAAGATT. Чтобы указать диапазон, мы можем использовать тот же синтаксис фигурных скобок и использовать общий шаблон где {N,Икс} находит предыдущий символ или группу междуNа такжеИксраз включительно. Например, TCG {2, 4} A будет соответствовать шаблонам TCGGA, TCGGGA, TCGGGA, но не TCGA или TCGGGGGA. Резюме этих метасимволов можно найти в таблице 1.
Подходим шаблон
Модуль re используется для написания регулярных выражений (регулярных выражений) в Python. Чтобы загрузить этот модуль, нам нужно использовать оператор импорта. Следующая строка кода должна быть включена вверху вашего кода:
импортре
Чтобы использовать инструмент из модуля регулярных выражений, необходимо добавить к нему имя модуля. Простейшая функция регулярного выражения re.search () определяет, существует ли шаблон где-то в строке. re.search () принимает 2 аргумента, которые являются строками. Первый аргумент - это шаблон, который вы хотите найти, а второй аргумент - это строка, в которой вы хотите искать. Для ясности, в приведенном ниже примере я включил 2 аргумента в качестве аргументов ключевого слова. Обычно нет необходимости включать эти ключевые аргументы. Для полноты я включил альтернативную синтаксическую версию, закомментированную.
Простой пример иллюстрируется в коде ниже; здесь мы ищем присутствие тринуклеотидного повтора оснований А в жестко закодированной переменной ДНК.
Результатом многих повторных вызовов функций является объект сопоставления. Если мы посмотрим на объект сопоставления выше, мы можем определить, было ли совпадение. Интервал идентифицирует индекс строки, где совпадения произошли, и совпадение идентифицирует точную строку, которая была найдена.
Поиск по регулярному выражению также можно использовать как часть условного оператора:
Извлечение значений совпадений
Часто в наших сценариях мы хотим не только определить, произошло ли совпадение, но и гдеточноэтот матч произошел. Мы также можем захотеть извлечь матчсам К счастью, Python упрощает извлечение значений объектов сопоставления, таких как позиции индекса совпадения и точную строку, которая соответствует. Это может быть достигнуто путем использования нескольких методов для объекта сопоставления.
Чередование и группы символов
re.search () также можно использовать для поиска более гибких шаблонов. В качестве примера, фермент рестрикции NCII распознает паттерн нуклеотидной последовательности «CCSGG», где нуклеотидный код «S» может быть либо C, либо G. Вместо того, чтобы писать два поиска с регулярным выражением, мы можем зафиксировать этот вариант, используя изменение. Здесь, чтобы представить ряд различных альтернатив, мы записываем альтернативы в круглых скобках и разделяем их, используя символ конвейера (метасимвол | также известен как оператор чередования, см. Таблицу 1).
Полезность чередующихся групп проистекает из их способности использоваться в качестве единиц повторений. Например, чтобы определить, ограничена ли последовательность стартовым и конечным кодоном и, следовательно, потенциально может быть открытой рамкой считывания, мы могли бы написать следующее выражение регулярного выражения:
Это регулярное выражение будет искать UAA, UAG и UGA в конце последовательности. Чтобы улучшить это регулярное выражение и убедиться, что стартовый и стоп-кодон находятся в одном кадре, мы можем изменить регулярное выражение на:
Это проверяет, что все символы между стартовым и стоп-кодоном кратны 3.
Группы персонажей
Группы символов также можно использовать для захвата вариаций в пределах одного шаблона. Рассмотрим консенсусный сайт N-гликозилирования в белках. Этот мотив последовательности имеет образец;За Asn следует что угодно, кроме Pro, затем Ser или Thr, за которым следует что угодно, кроме Pro.
Используя соответствующие однобуквенные аминокислотные коды с группами символов, мы можем написать эту схему следующим образом:
Этот шаблон будет идентифицировать одиночный буквенный код N, за которым следует любой символ, который не является P (см. Таблицу 1, группы символов с отрицанием), за которым следует либо S, либо T, а затем любой символ, не являющийся P. Пара изквадратные скобкисо списком символов внутри них может представлятьлюбойодин из этих символов (см. таблицу 1).
Сила регулярных выражений
Настоящая сила регулярных выражений используется, когда эти инструменты используются вместе. Рассмотрим следующий сценарий. Многие наследственные нейродегенеративные расстройства человека, такие как болезнь Хантингтона (HD), были связаны с аномальным увеличением числа тринуклеотидных повторов в определенных генах. Патологическая тяжесть HD коррелирует с количеством (CAG)Nповторяется в экзоне-1 генаHTTкоторый кодирует белок Хантингтон. При болезни Хантингтона большее количество повторов означает более раннее начало заболевания и более быстрое прогрессирование заболевания. Кодон CAG определяет глютамин, а HD относится к широкому классу полиглутаминовых заболеваний. Здоровые (дикого типа) варианты этого гена имеют от 6 до 35 тандемных повторов, тогда как более 35 повторов фактически гарантируют заболевание.
Мы можем использовать регулярные выражения, чтобы расшифровать число повторений полиглутамина. Во-первых, это включает в себя написание шаблона для определения числа тринуклеотидных повторов выше установленного порога.
Кодон CAA также кодирует глютамин, поэтому в приведенном выше htt_pattern мы должны использовать | оператор чередования. Затем мы можем использовать обозначение фигурных скобок, рассмотренное выше, чтобы указать, сколько раз мы хотим найти этот шаблон. Здесь я выбрал 18 или более раз,сознательновыходя за верхний предел.
Я сначала искал в базе данных нуклеотидов NCBI дляHTTПоследовательность мРНК и загрузил его в мой рабочий каталог. Затем я прочитал эту последовательность и использовал свой шаблон для определения длины тандемных повторов глутамина, которые выше 18. Для ясности я выделил совпадение в файле NCBI FASTA. Я также использовал функцию re.findall (), так как re.search () найдет только первое вхождение, и в этом случае возможно, что найдется много совпадений.
Вывод:
Этот урок предоставил краткое введение в то, как регулярное выражение может быть применено конкретно в генетике. Знания в регулярных выражениях легко переносимы, в частности синтаксические формы и функциональные возможности ведут себя примерно одинаково в Python и во многих других основных языках программирования, таких как Perl и R.
Оригинальная статья
функция re.
MatchObject.group () в Python Regex
Метод re.MatchObject.group () возвращает полную сопоставленную подгруппу по умолчанию или кортеж сопоставленных подгрупп в зависимости от количества аргументов
Синтаксис: re.MatchObject.group ([группа])
Параметр:
- группа: (необязательно) группа по умолчанию равна нулю (это означает, что она вернет полную согласованную строку).Верните -1, если группа существует, но не участвовала в совпадении.
Возврат: Полное совпадение по умолчанию, иначе одна или несколько совпадающих подгрупп в зависимости от аргументов.
IndexError: Если номер группы, переданный в качестве аргумента, является отрицательным или больше, чем количество групп, определенных в шаблоне соответствия, то возникает исключение IndexError.
AttributeError: Если соответствующий шаблон не найден, он вызывает AttributeError.
Рассмотрим пример ниже:
Пример 1:
Программа для печати имени пользователя, имени компании и домена из электронного адреса
Python3
импорт
повторно
match_object
=
re.match (r
'(\ w +) @ (\ w +) \. (\ w +)'
,
'[email protected]'
)
печать
(match_object.group ())
печать
(match_object.group (
1
))
печать
(match_object. группа (
2
))
печать
(match_object.group (
3
))
печать
(match_object.group (
1
,
2
,
3
))
Выход:
[email protected] имя пользователя geekforgeeks org ('имя пользователя', 'geekforgeeks', 'org')
Пора разобраться в вышеуказанной программе.Мы используем метод re.match () , чтобы найти совпадение в заданной строке (' [email protected] '), ' w ' указывает, что мы ищем алфавитный символ, а ' + 'означает, что мы ищем непрерывные буквенные символы в данной строке. Обратите внимание, что скобка « () » используется для определения различных подгрупп, в приведенном выше примере у нас есть три подгруппы в шаблоне соответствия. В результате мы получаем рэ.MatchObject , который хранится в match_object.
Примечание: Чтобы узнать больше о шаблонах регулярных выражений, обратитесь к Python regex
В зависимости от переданных аргументов групповой метод возвращает нам разные строки, а также возвращает кортеж совпадающих строк.
Пример 2:
Если мы передадим недопустимый номер группы в аргументе метода, мы получим исключение IndexError.
Python3
импорт
повторно
match_object
=
re.match (r
'(\ w +) @ (\ w +) \. (\ w +)'
,
'[email protected]'
)
печать
(match_object. group (
7
))
Выход:
Traceback (последний вызов последний): Файл "/ home / 8da42759204c98da7baa88422a4a74e0.ру », строка 17, в печать (match_object.group (7)) IndexError: такой группы нет
Внимание компьютерщик! Укрепите свои основы с помощью курса Python Programming Foundation и изучите основы.
Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS .
Учебное пособие по
Regex - Именованные группы захвата
Почти все современные механизмы регулярных выражений поддерживают нумерованные группы захвата и нумерованные обратные ссылки.Длинные регулярные выражения с большим количеством групп и обратных ссылок могут быть трудночитаемыми. Их может быть особенно сложно поддерживать, поскольку добавление или удаление группы захвата в середине регулярного выражения приводит к нарушению номеров всех групп, следующих за добавленной или удаленной группой.
Модуль Python re был первым, кто предложил решение: именованные группы захвата и именованные обратные ссылки. (? P
group) записывает совпадение группы в обратную ссылку «name». имя должно быть буквенно-цифровой последовательностью, начинающейся с буквы.>] *>. *? (? P = tag)>. Платформа .NET также поддерживает именованный захват. Разработчики Microsoft изобрели свой собственный синтаксис, вместо того, чтобы следовать синтаксису, впервые предложенному Python и скопированному PCRE (единственными двумя механизмами регулярных выражений, которые в то время поддерживали именованный захват). (?
group) или (? 'name'group) записывает совпадение группы в обратную ссылку «name». Именованная обратная ссылка - \ k <имя> или \ k'name '. По сравнению с Python в синтаксисе именованных групп отсутствует буква P.Синтаксис именованных обратных ссылок больше похож на синтаксис нумерованных обратных ссылок, чем на то, что использует Python. Вы можете заключить имя в одинарные кавычки или угловые скобки. Это абсолютно не влияет на регулярное выражение. Вы можете использовать оба стиля как взаимозаменяемые. Синтаксис с использованием угловых скобок предпочтительнее в языках программирования, которые используют одинарные кавычки для разделения строк, в то время как синтаксис с использованием одинарных кавычек предпочтительнее при добавлении вашего регулярного выражения в файл XML, так как это минимизирует количество экранирований, которые вам нужно сделать для форматирования вашего регулярного выражения. как буквальная строка или как содержимое XML. Поскольку Python и .NET представили свой собственный синтаксис, мы называем эти два варианта «синтаксисом Python» и «синтаксисом .NET» для именованного захвата и именованных обратных ссылок. Сегодня многие другие разновидности регулярных выражений скопировали этот синтаксис.
Perl 5.10 добавил поддержку синтаксиса Python и .NET для именованного захвата и обратных ссылок. Он также добавляет еще два синтаксических варианта для именованных обратных ссылок: \ k {one} и \ g {two}. Нет никакой разницы между пятью синтаксисами именованных обратных ссылок в Perl.Все можно использовать как взаимозаменяемые. В тексте замены вы можете интерполировать переменную $ + {name}, чтобы вставить текст, совпадающий с именованной группой захвата.
PCRE 7.2 и выше поддерживают весь синтаксис именованного захвата и обратных ссылок, который поддерживает Perl 5.10. Старые версии PCRE поддерживали синтаксис Python, хотя в то время он не был «совместим с Perl». Такие языки, как PHP, Delphi и R, реализующие поддержку регулярных выражений с использованием PCRE, также поддерживают весь этот синтаксис. К сожалению, ни PHP, ни R не поддерживают именованные ссылки в тексте замены.Вам нужно будет использовать нумерованные ссылки на названные группы. PCRE вообще не поддерживает поиск и замену.
Java 7 и XRegExp скопировали синтаксис .NET, но только вариант с угловыми скобками. Ruby 1.9 и поддерживает оба варианта синтаксиса .NET. Версия JGsoft поддерживает синтаксис Python и оба варианта синтаксиса . NET.
Boost 1.42 и более поздние версии поддерживают именованные группы захвата с использованием синтаксиса .NET с угловыми скобками или кавычками и именованные обратные ссылки с использованием синтаксиса \ g с фигурными скобками из Perl 5.10. Boost 1.47 дополнительно поддерживает обратные ссылки с использованием синтаксиса \ k с угловыми скобками и кавычками из .NET. Повышение 1,47 позволило этим вариантам множиться. Boost 1.47 позволяет указывать именованные и нумерованные обратные ссылки с помощью \ g или \ k и фигурных скобок, угловых скобок или кавычек. Таким образом, Boost 1.47 и более поздние версии имеют шесть вариантов синтаксиса обратной ссылки поверх базового синтаксиса \ 1. Это ставит Boost в конфликт с Ruby, PCRE, PHP, R и JGsoft, которые рассматривают \ g с угловыми скобками или кавычками как вызов подпрограммы.
Номера для именованных групп захвата
Смешение именованных и пронумерованных групп захвата не рекомендуется, так как нумерация групп несовместима. Если группе не нужно иметь имя, сделайте ее не захватывающей, используя синтаксис (?: Group). В .NET вы можете сделать все безымянные группы не захватывающими, установив RegexOptions.ExplicitCapture. В Delphi установите roExplicitCapture. С XRegExp используйте флаг / n. Perl поддерживает / n, начиная с Perl 5.22. С помощью PCRE установите PCRE_NO_AUTO_CAPTURE.Версия JGsoft и .NET поддерживают модификатор режима (? N). Если вы отключите захват всех безымянных групп, вы можете пропустить этот раздел и избавить себя от головной боли.
Большинство разновидностей нумеруют как именованные, так и безымянные группы захвата, считая их открывающие скобки слева направо. Добавление именованной группы захвата к существующему регулярному выражению по-прежнему нарушает количество безымянных групп. В .NET, однако, безымянным группам захвата сначала присваиваются номера, считая их открывающие скобки слева направо, пропуская все именованные группы.После этого именованным группам присваиваются номера, которые следуют за счетом открывающих скобок именованных групп слева направо.
Механизм регулярных выражений JGsoft скопировал синтаксис Python и .NET в то время, когда только Python и PCRE использовали синтаксис Python, и только .NET использовал синтаксис .NET. Поэтому он также скопировал поведение нумерации как Python, так и .NET, так что регулярные выражения, предназначенные для Python и .NET, сохраняли свое поведение. Он нумерует именованные группы в стиле Python вместе с безымянными, как это делает Python.После этого он нумерует именованные группы в стиле .NET, как это делает .NET. Эти правила применяются, даже если вы смешиваете оба стиля в одном регулярном выражении.
В качестве примера регулярное выражение (a) (? P
b) (c) (? P d) соответствует abcd, как ожидалось. Если вы выполните поиск и замену с этим регулярным выражением и заменой \ 1 \ 2 \ 3 \ 4 или $ 1 $ 2 $ 3 $ 4 (в зависимости от вкуса), вы получите abcd. Все четыре группы были пронумерованы слева направо от одного до четырех. С .NET framework все немного сложнее. Регулярное выражение (a) (?
b) (c) (? d) снова соответствует abcd. Однако, если вы выполните поиск и замену, указав 1 доллар 2 3 4 доллара в качестве замены, вы получите acbd. Сначала безымянные группы (a) и (c) получили числа 1 и 2. Затем названные группы «x» и «y» получили числа 3 и 4. Во всех других вариантах, которые копировали синтаксис .NET, regex (a) (?
b) (c) (? d) по-прежнему соответствует abcd. Но во всех этих вариантах, кроме JGsoft, замена \ 1 \ 2 \ 3 \ 4 или $ 1 $ 2 $ 3 $ 4 (в зависимости от вкуса) дает вам abcd.Все четыре группы были пронумерованы слева направо. В PowerGREP, который использует разновидность JGsoft, именованные группы захвата играют особую роль. Группы с одинаковыми именами используются всеми регулярными выражениями и текстами замены в одном действии PowerGREP. Это позволяет ссылаться на захваченные именованной группой захвата в одной части действия в более поздней части действия. Из-за этого PowerGREP вообще не разрешает нумерованные ссылки на именованные группы захвата. При смешивании именованных и нумерованных групп в регулярном выражении нумерованные группы по-прежнему нумеруются после Python и.NET, как это всегда бывает с JGsoft.
Несколько групп с одинаковым именем
Платформа .NET и разновидность JGsoft позволяют нескольким группам в регулярном выражении иметь одно и то же имя. Все группы с одинаковым именем используют одно и то же хранилище для совпадающего текста. Таким образом, обратная ссылка на это имя соответствует тексту, который был сопоставлен группой с этим именем, которая что-то зафиксировала последним. Ссылка на имя в замещающем тексте вставляет текст, соответствующий группе с тем именем, которая была последней, кто что-то зафиксировал.
Perl и Ruby также допускают группы с одинаковыми именами. Но эти ароматы используют только дым и зеркала, чтобы создать впечатление, будто все группы с одним и тем же названием действуют как одна. На самом деле группы раздельные. В Perl обратная ссылка соответствует тексту, захваченному самой левой группой в регулярном выражении с тем именем, которое что-то соответствует. В Ruby обратная ссылка соответствует тексту, захваченному любой из групп с этим именем. Возврат заставляет Ruby пробовать все группы.
Итак, в Perl и Ruby вы можете осмысленно использовать группы с одинаковым именем, только если они находятся в разных альтернативах в регулярном выражении, так что только одна из групп с таким именем могла когда-либо захватывать любой текст.Затем обратные ссылки на эту группу разумно соответствуют тексту, захваченному группой.
Например, если вы хотите сопоставить «a», за которым следует цифра 0..5, или «b», за которым следует цифра 4..7, и вас интересует только цифра, вы можете использовать регулярное выражение a ( ? <цифра> [0-5]) | b (? <цифра> [4-7]). В этих четырех вариантах группа с именем «цифра» затем выдаст вам совпавшую цифру 0..7, независимо от буквы. Если вы хотите, чтобы за этим совпадением следовала c и точно такая же цифра, вы можете использовать (?: A (?
[0-5]) | b (? [4-7])) c \ k <цифра> PCRE по умолчанию не допускает дублирования именованных групп. PCRE 6.7 и более поздних версий разрешают их, если вы включите эту опцию или используете модификатор режима (? J). Но до PCRE 8.36 это было не очень полезно, поскольку обратные ссылки всегда указывали на первую группу захвата с таким именем в регулярном выражении, независимо от того, участвовала ли она в сопоставлении. Начиная с PCRE 8.36 (и, следовательно, PHP 5.6.9 и R 3.1.3), а также в PCRE2, обратные ссылки указывают на первую группу с таким именем, которая фактически участвовала в сопоставлении. Хотя PCRE и Perl обрабатывают повторяющиеся группы в противоположных направлениях, конечный результат будет таким же, если вы последуете совету использовать только группы с одинаковыми именами в разных вариантах.
Boost позволяет дублировать именованные группы. До Boost 1.47 это было бесполезно, поскольку обратные ссылки всегда указывали на последнюю группу с таким именем, которое появляется перед обратной ссылкой в регулярном выражении. В Boost 1.47 и более поздних версиях обратные ссылки указывают на первую группу с таким именем, которая фактически участвовала в матче, как в PCRE 8. 36 и более поздних версиях.
Python, Java и XRegExp 3 не позволяют нескольким группам использовать одно и то же имя. Это приведет к ошибке компиляции регулярного выражения. XRegExp 2 допускал их, но не обрабатывал их правильно.
В Perl 5.10, PCRE 8.00, PHP 5.2.14 и Boost 1.42 (или более поздних версиях) лучше всего использовать группу сброса ветвления, когда вы хотите, чтобы группы в разных альтернативах имели одинаковое имя, как в (? | a (? <цифра> [0-5]) | b (? <цифра> [4-7])) c \ k <цифра>. С этим специальным синтаксисом - группа, открытая с помощью (? | Вместо (?: - две группы с именем «цифра» действительно являются одной и той же группой. Тогда обратные ссылки на эту группу всегда обрабатываются правильно и последовательно между этими разновидностями.(Более старые версии PCRE и PHP могут поддерживать группы сброса ветвей, но некорректно обрабатывают повторяющиеся имена в группах сброса ветвей.)
Сделайте пожертвование
Этот веб-сайт только что сэкономил вам поездку в книжный магазин? Сделайте пожертвование на поддержку этого сайта, и вы получите неограниченного доступа к этому сайту без рекламы!
Python Re Группы | Finxter
В этом руководстве объясняется все, что вам нужно знать о совпадающих группах в пакете Python
re
для регулярных выражений. Возможно, вы также читали термин «группы захвата» , который указывает на ту же концепцию.По мере того, как вы читаете руководство, вы также можете посмотреть обучающее видео, в котором я объясняю все простым способом:
Статья по теме: Python Regex Superpower - полное руководство
Вы хотите овладеть суперсилой регулярных выражений? Посмотрите мою новую книгу Самый разумный способ изучения регулярных выражений в Python с инновационным трехэтапным подходом для активного обучения: (1) изучите главу книги, (2) решите загадку кода и (3) ) посмотрите обучающее видео с главой.
Итак, начнем с основ:
Соответствующая группа ()
Что такое соответствующая группа?
Подобно тому, как вы используете круглые скобки для структурирования математических выражений,
(2 + 2) * 2
против2 + (2 * 2)
, вы используете круглые скобки для структурирования регулярных выражений. Пример регулярного выражения, которое делает это, -'a (b | c)'
. Весь контент, заключенный в открывающие и закрывающие круглые скобки, называется группой соответствия (или группой захвата ).В одном регулярном выражении может быть несколько совпадающих групп. И вы даже можете иметь иерархические группы соответствия, например'a (b | (cd))'
.Одно из больших преимуществ совпадающей группы состоит в том, что она захватывает совпадающую подстроку. Вы можете получить его в других частях регулярного выражения или после анализа результата соответствия всего регулярного выражения.
Давайте рассмотрим краткий пример самого простого использования совпадающей группы - для структурирования регулярного выражения.
Допустим, вы создали регулярное выражение
b? (A.) *
с соответствующей группой(a.)
, которая соответствует всем шаблонам, начинающимся с нуля или одному вхождению символа'b'
, и произвольному количеству двухсимвольных последовательностей, начинающихся с символа'a'
. Следовательно, строки'bacacaca'
,'aaaa'
,''
(пустая строка) и'Xababababab'
соответствуют вашему регулярному выражению.Использование круглых скобок для структурирования регулярного выражения интуитивно понятно и должно быть естественным, поскольку применяются те же правила, что и для арифметических операций.Однако существует более продвинутое использование групп регулярных выражений: получение.
Вы можете получить совпадающий контент каждой совпадающей группы. Естественно возникает следующий вопрос:
Как получить первую подходящую группу?
Есть два сценария, когда вы хотите получить доступ к содержимому ваших совпадающих групп:
- Получите доступ к соответствующей группе в шаблоне регулярного выражения, чтобы повторно использовать частично согласованный текст из одной группы в другом месте.
- Получите доступ к соответствующей группе после всей операции сопоставления, чтобы проанализировать сопоставленный текст в вашем коде Python.
В первом случае вы просто получаете первую совпадающую группу со специальной последовательностью
\ number
. Например, чтобы получить первую совпадающую группу, вы должны использовать специальную последовательность\ 1
. Вот пример:>>> import re >>> re. search (r '(j.n) is \ 1', 'jon is jon') <объект re.Match; span = (0, 10), match = 'jon is jon'>
Вы будете часто использовать эту функцию, потому что она дает вам гораздо больше возможностей выражения: например, вы можете искать имя в тексте на основе заданного шаблона, а затем специально обрабатывать это имя в остальной части текста (и не все другие имена, которые также подошли бы к шаблону).
Обратите внимание, что нумерация групп начинается с
\ 1
, а не с\ 0
- редкое исключение из правила, что при программировании вся нумерация начинается с 0.Во втором случае , вы хотите узнать содержимое первой группы после всего совпадения. Как ты это делаешь?
Ответ также прост: используйте метод
m.group (0)
для соответствующего объектаm
. Вот пример:>>> import re >>> м = ре. search (r '(j.n)', 'jon is jon') >>> m.group (1) 'jon'
Нумерация работает согласованно с ранее введенной нумерацией групп регулярных выражений: начните с идентификатора 1, чтобы получить доступ к содержимому первой группы.
Как получить все остальные совпадающие группы?
Опять же, когда вы задаете этот вопрос, есть два разных намерения:
- Получите доступ к соответствующей группе в шаблоне регулярного выражения, чтобы повторно использовать частично согласованный текст из одной группы в другом месте.
- Получите доступ к соответствующей группе после всей операции сопоставления, чтобы проанализировать сопоставленный текст в вашем коде Python.
В первом случае вы используете специальную последовательность
\ 2
для доступа ко второй совпадающей группе,\ 3
для доступа к третьей совпадающей группе и\ 99
для доступа к девяносто девятой совпадающей группе .Вот пример:
>>> import re >>> re.search (r '(j ..) (j ..) \ s + \ 2', 'jon jim jim')
>>> re.search (r '(j ..) (j ..) \ s + \ 2', 'jon jim jon') >>> Как видите, специальная последовательность \ 2 относится к совпадающему содержимому второй группы
'jim'
.Во втором случае вы можете просто увеличить идентификатор, чтобы получить доступ к другим группам соответствия в вашем коде Python:
>>> import re >>> m = re.search (r '(j ..) (j ..) \ s + \ 2', 'jon jim jim') >>> м. группа (0) 'Джон Джим Джим' >>> m.group (1) 'Джон' >>> m.group (2) 'Джим'
Этот код также показывает интересную особенность: если вы используете идентификатор 0 в качестве аргумента метода
m.group (0)
, модуль регулярных выражений выдаст вам содержимое всего совпадения. Вы можете думать об этом как о первой группе, представляющей весь матч.Именованные группы: (? P
…) и (? P = name) Доступ к захваченной группе с использованием записи
\ номер
не всегда удобен, а иногда даже невозможен (например, если у вас более 99 групп в вашем регулярном выражении).Основным недостатком регулярных выражений является то, что их трудно читать. Поэтому важно знать о различных настройках для улучшения читаемости.Одной из таких оптимизаций является именованная группа. На самом деле это так: совпадающая группа, которая отражает часть совпадения, но с одним поворотом: у нее есть имя. Теперь вы можете использовать это имя для доступа к захваченной группе на более позднем этапе вашего шаблона регулярного выражения. Это может улучшить читаемость регулярного выражения.
импорт ре шаблон = '(? P <цитата> ["\']).* (? P = цитата) ' text = 'Она сказала "привет"' печать (повторный поиск (шаблон, текст)) # <объект re.Match; span = (9, 13), match = '"привет"'>
Код ищет подстроки, заключенные в одинарные или двойные кавычки. Сначала вы сопоставляете начальную цитату, используя регулярное выражение
["\ ']
. Вы избегаете одинарной кавычки,\'
, чтобы механизм регулярных выражений Python не предполагал (ошибочно), что одинарная кавычка указывает на конец строки Затем вы используете ту же группу для сопоставления закрывающей кавычки одного и того же символа (одинарной или двойной кавычки).Группы без захвата (?:…)
В предыдущих примерах вы видели, как сопоставлять и захватывать группы с помощью круглых скобок
(. ..)
. Вы узнали, что каждое совпадение этого основного оператора группы фиксируется, чтобы вы могли извлечь его позже в регулярном выражении с помощью специальных команд\ 1
,\ 2
,…,\ 99
или после совпадения в сопоставленный объектм
методомм. группа (1)
,м. группа (2)
и так далее.Но что, если это вам не нужно? Что, если вам просто нужно сохранить порядок в шаблоне регулярного выражения, но вы не хотите захватывать содержимое соответствующей группы?
Простым решением является групповая операция без захвата
(?: ...)
. Вы можете использовать его так же, как операцию группы захвата(...)
. Вот пример:>>> import re >>> re.search ('(?: python | java) is great', 'python is great. java is great.')
Группа без захвата существует с единственной целью - структурировать регулярное выражение. Вы не можете использовать его содержимое позже:
>>> m = re.search ('(?: Python | java) is great', 'python is great. Java is great.') >>> m.group (1) Отслеживание (последний вызов последний): Файл "
", строка 1, в м. группа (1) IndexError: такой группы нет >>> Если вы попытаетесь получить доступ к содержимому группы без захвата, механизм регулярных выражений выдаст ошибку
IndexError: нет такой группы
.Конечно, есть простая альтернатива группам без захвата. Вы можете просто использовать обычную (захватывающую) группу, но без доступа к ее содержимому. Лишь в редких случаях снижение производительности из-за захвата ненужной группы будет иметь какое-либо значимое влияние на ваше приложение в целом.
Положительный просмотр вперед (? =…)
Концепция предвидения - очень действенная, и любой продвинутый программист должен ее знать. Мой друг недавно сказал мне, что он написал сложное регулярное выражение, которое игнорирует порядок появления двух слов в заданном тексте.Это сложная проблема, и без концепции опережающего просмотра результирующий код будет сложным и трудным для понимания. Однако концепция опережающего просмотра упрощает запись и чтение этой проблемы.
Но обо всем по порядку: как работает утверждение lookahead?
При обычной обработке регулярных выражений регулярное выражение сопоставляется слева направо. Механизм регулярных выражений «потребляет» частично совпадающие подстроки. Потребляемая подстрока не может быть сопоставлена какой-либо другой частью регулярного выражения.
Рисунок: Простой пример опережающего просмотра. Механизм регулярных выражений частично сопоставляет («потребляет») строку. Затем он проверяет, можно ли сопоставить оставшийся образец без фактического сопоставления с ним.
Думайте об утверждении опережающего просмотра как о непотребляющем сопоставлении с шаблоном. Механизм регулярных выражений выполняет поиск шаблона слева направо. В каждой точке у него есть одна «текущая» позиция, чтобы проверить, является ли эта позиция первой позицией оставшегося совпадения.Другими словами, механизм регулярных выражений пытается «использовать» следующий символ как (частичное) совпадение с шаблоном.
Преимущество выражения просмотра вперед в том, что оно ничего не потребляет. Он просто «смотрит вперед», начиная с текущей позиции, будет ли теоретически соответствовать шаблону просмотра вперед. Если этого не произойдет, обработчик регулярных выражений не сможет двигаться дальше. Затем он «возвращается» - это просто причудливый способ сказать: он возвращается к предыдущему решению и пытается сопоставить что-то еще.
Пример положительного просмотра вперед: как сопоставить два слова в произвольном порядке?
Что если вы хотите найти в заданном тексте шаблон A И шаблон B, но без определенного порядка? Если оба шаблона встречаются где-нибудь в строке, вся строка должна быть возвращена как совпадение.
Теперь это немного сложнее, потому что любой шаблон регулярного выражения упорядочен слева направо. Простое решение - использовать утверждение опережения (?. * A), чтобы проверить, появляется ли регулярное выражение A где-нибудь в строке.(Обратите внимание, что мы предполагаем, что в качестве шаблона. * Однострочная строка не соответствует символу новой строки по умолчанию.)
Давайте сначала рассмотрим минимальное решение для проверки двух шаблонов в любом месте строки (скажем, шаблонов «привет» И «ты»).
>>> import re >>> pattern = '(? =. * привет) (? =. * you)' >>> re.findall (шаблон, привет, как дела?) [] >>> re.findall (узор, привет, как дела?) ['']
В первом примере оба слова не появляются.Во втором примере да.
Давайте вернемся к выражению (? =. * Hi) (? =. * You), чтобы сопоставить строки, содержащие как «hi», так и «you». Почему это работает?
Причина в том, что выражения просмотра вперед ничего не потребляют. Сначала вы ищите произвольное количество символов. *, А затем слово hi. Но поскольку механизм регулярных выражений ничего не использовал, он все еще находится на той же позиции в начале строки . Итак, вы можете повторить то же самое для слова вы.
Обратите внимание, что этот метод не заботится о порядке двух слов:
>>> import re >>> pattern = '(? =. * привет) (? =. * you)' >>> re.findall (узор, привет, как дела?) [''] >>> re.findall (шаблон, 'ты как? привет!') ['']
Независимо от того, какое слово «привет» или «вы» появляется первым в тексте, механизм регулярных выражений находит оба слова.
Вы можете спросить: почему на выходе пустая строка? Причина в том, что механизм регулярных выражений не использовал никаких символов.Он просто проверил опережающие просмотры. Поэтому простое решение - использовать все символы следующим образом:
>>> import re >>> pattern = '(? =. * привет) (? =. * you). *' >>> re.findall (узор, "высоко летишь") ["вы летите высоко"]
Теперь вся строка является совпадением, потому что после проверки просмотра вперед с помощью ‘(? =. * Hi) (? =. * You)’ вы также потребляете всю строку ‘. *’.
Отрицательный взгляд вперед (?!…)
Отрицательный просмотр вперед работает так же, как и положительный просмотр вперед - только он проверяет, что данный шаблон регулярного выражения не происходит, , а не , при движении вперед из определенной позиции.
Вот пример:
>>> import re >>> re.search ('(?!. * hi. *)', 'привет, поздоровайся?') <объект re.Match; промежуток = (8, 8), совпадение = ''>
Шаблон отрицательного просмотра вперед
(?!. * Hi. *)
гарантирует, что при продвижении вперед в строке не будет вхождения подстроки'hi'
. Первая позиция, где это удерживается, - это позиция 8 (сразу после второй'h'
). Как и положительный просмотр вперед, отрицательный просмотр вперед не использует никаких символов, поэтому результатом является пустая строка (которая является допустимым совпадением с шаблоном).Можно даже комбинировать несколько отрицательных опережающих просмотров следующим образом:
>>> re.search ('(?!. * Привет. *) (?! \?).', 'Привет, привет?') <объект re.Match; span = (8, 9), match = 'i'>
Вы ищите позицию, в которой нет ни слова «привет», ни знака вопроса. На этот раз мы используем произвольный символ, поэтому в результате будет найден символ
'i'
.Флаги группы (? AiLmsux:…) и (? AiLmsux)
Вы можете управлять обработчиком регулярных выражений с помощью аргумента flags функции re.findall (), re.search () или re.match (). Например, если вас не интересует использование заглавных букв в совпадающей подстроке, вы можете передать флаг
re.IGNORECASE
методам регулярного выражения:>>> re. findall ('PYTHON', 'python отличный', flags = re.IGNORECASE) ['питон']
Но использование глобального флага для всего регулярного выражения не всегда оптимально. Что делать, если вы хотите игнорировать регистр только для определенного подрегексного выражения?
Это можно сделать с помощью флагов группы: a, i, L, m, s, u и x.Каждый флаг группы имеет свое значение:
Синтаксис Значение a
Если вы не используете этот флаг, специальные символы регулярного выражения Python \ w, \ W, \ b, \ B, \ d, \ D, \ s и \ S будут соответствовать символам Unicode. Если вы используете этот флаг, эти специальные символы будут соответствовать только символам ASCII - как следует из названия. i
Если вы используете этот флаг, механизм регулярных выражений будет выполнять сопоставление без учета регистра. ’Соответствует началу каждой строки (а не только ее началу). То же самое относится и к регулярному выражению конца строки «$», которое теперь соответствует также и в конце каждой строки в многострочной строке. s
Без использования этого флага регулярное выражение с точкой ‘.’ Соответствует всем символам, кроме символа новой строки ‘\ n’. Включите этот флаг, чтобы действительно соответствовать всем символам, включая символ новой строки. x
Чтобы улучшить читаемость сложных регулярных выражений, вы можете разрешить комментарии и (многострочное) форматирование самого регулярного выражения.Это возможно с помощью этого флага: все пробельные символы и строки, начинающиеся с символа «#», игнорируются в регулярном выражении. Например, если вы хотите отключить дифференциацию заглавных букв, вы будете использовать флаг
i
следующим образом:>>> re. findall ('(? I: PYTHON)', 'питон великолепен') ['питон']
Вы также можете отключить регистрацию для всего регулярного выражения с помощью «флага глобальной группы»
(? I)
следующим образом:>>> re.findall ('(? i) PYTHON', 'питон великолепен') ['питон']
Куда идти дальше?
Сводка : вы узнали о группах сопоставления для структурирования регулярного выражения и захвата частей результата сопоставления. Затем вы можете получить захваченные группы с синтаксисом
\ number
в самом шаблоне регулярного выражения и с синтаксисомm.group (i)
в коде Python на более позднем этапе.Чтобы изучить основы Python, посетите мою бесплатную академию электронной почты Python с множеством продвинутых курсов, включая видеоурок по регулярным выражениям в вашем INBOX.
Присоединяйтесь к 20 000+ амбициозным программистам бесплатно!
Работая исследователем распределенных систем, доктор Кристиан Майер обнаружил свою любовь к обучению студентов, изучающих информатику.
Чтобы помочь студентам достичь более высокого уровня успеха в Python, он основал сайт обучения программированию Finxter.com. Он является автором популярной книги по программированию Python One-Liners (NoStarch 2020), соавтором серии самоизданных книг о Python для кофе-брейков, энтузиаст информатики, фрилансер и владелец одного из 10 крупнейших блогов по Python в мире.
Его страстью являются письмо, чтение и кодирование. Но его самая большая страсть - служить начинающим программистам через Finxter и помогать им повышать свои навыки. Вы можете присоединиться к его бесплатной электронной академии здесь.
Регулярные выражения Python: примеры и справочная информация
Примеры использования регулярных выражений в Python.
Если не указано иное, в примерах используется Python 3 . Посмотреть все примеры на этом ноутбуке jupyter
Строка соответствует регулярному выражению
Шаблон должен соответствовать , начиная с строки.
Используйте повторное сопоставление
(шаблон, строка)
. Этот метод возвращает объект соответствия в случае совпадения илиNone
, если совпадения не было.Пример шаблона: один или несколько буквенно-цифровых символов
импорт ре # совпадение (шаблон, строка) если re.match ('w +', 'foobar'): # матч еще: # не совпадает
Вся строка соответствует регулярному выражению
В этом случае совпадение будет только в том случае, если строка полностью соответствует заданному шаблону.
Пример шаблона: "foo", за которым следует одна или несколько цифр
Если на Python 3. 4 или новее, используйте
re.fullmatch (шаблон, строка)
:импорт ре # Версия Python> = 3.4 # соответствует, потому что th строка ПОЛНОСТЬЮ соответствует шаблону re.fullmatch ('фу \ д +', 'фу123') # >>> <_sre.SRE_Match object; span = (0, 6), match = 'foo123'> # нет совпадений, потому что хотя шаблон совпадает с началом # строка, в конце есть лишние символы ("полоса") ре.foo \ d + $ ',' foo123bar ') # >>> Нет
Строка содержит регулярное выражение
Чтобы узнать, присутствует ли регулярное выражение в строке, используйте
re.search (pattern, string)
:Пример шаблона: последовательность из 3 цифр:
импорт ре # возвращает совпадение re.search ('\ d {3}', 'foo 123 bar') # >>> <_sre.SRE_Match object; span = (4, 7), match = '123'> # нет совпадений, не возвращает None re.search ('\ d {3}', 'foo 1 23 bar') # >>> Нет
Используйте
re. (\ w {3}) - (\ w {3}) $ ", строка1)
если совпадает:
# индекс соответствия начинается с 1
first_group_match = match.group (1)
# abcsecond_group_match = match.group (2)
# defпечать (совпадение_первой_группы + «И» + совпадение_второй_группы)
# выводит: "abc AND def"
Может быть извлечено только первое вхождение захвата.
Используйте
re.search (шаблон, строка)
и.group ()
.Пример: цифры захвата, за которыми следует
"x"
импорт ре # одна или несколько цифр, за которыми следует 'x' pat = r "(\ d +) x" # второе вхождение ('456') не фиксируется.re.search (pat, "123x 456x"). group (1) # >>> "123"
Соответствует шаблону в любом месте строки, но только один раз .
Используйте
re.search (шаблон, строка)
вместоre. match
Пример шаблона: буква «b», за которой следуют два буквенно-цифровых символа
импорт ре шаблон = r'b \ w {2} ' match = re.search (шаблон, "foo bar baz quux") # >>> <_sre.SRE_Match object; span = (4, 7), match = 'bar'> матч.группа (0) # >>> 'бар'
Используйте
re.findall (шаблон, строка)
. Обратите внимание, что этот возвращает список строк , а не список объектовMatch
.импорт ре # буква 'b', за которой следуют два буквенно-цифровых символа шаблон = r'b \ w {2} ' re.findall (шаблон, "foo bar baz quux") # >>> ['bar', 'baz']
Примечание :
re.finditer (шаблон, строка)
работает точно так же, но вместо простого списка сопоставленных строк возвращается итераторMatch
объектов.Чтобы извлечь все совпадения регулярного выражения в строке, возвращает
Match
объектов , используйтеre. finditer (шаблон, строка)
:импорт ре # буква 'b', за которой следуют два буквенно-цифровых символа шаблон = r'b \ w {2} ' match = re.finditer (шаблон, 'foo bar baz quux') # завернуть результат в список, потому что это генератор список (совпадения) # >>> [<_sre.SRE_Match object; span = (4, 7), match = 'bar'>, # <_sre.SRE_Match объект; span = (8, 11), match = 'baz'>]
Заменить регулярное выражение в строке
Это заменит всех вхождений регулярного выражения в строке.>] +> ',' ',' foo
bar ')
# возвращает 'foo bar'
Заменить только первое вхождение регулярного выражения
Используйте
re.sub (шаблон, замена, строка, количество = 1)
Заменить захваченную группу
Группы обозначаются следующим образом:
'\ 1'
для первой группы,'\ 2'
для второй группы и т. Д.Обратите внимание на использование модификатора
r ''
для струн.Группы индексируются 1 (они начинаются с 1, а не с 0)
Пример шаблона: сопоставить имена файлов (например,. +) \. (. +) $ ‘
# замените расширение на «MYEXT»
re.sub (шаблон, r ‘\ 1.MYEXT’, «foo.txt»)
# возвращает foo.MYEXT# замените имя файла на «MYFILE»
re.sub (шаблон, r’MYFILE. \ 2 ‘, «foo.txt»)
# возвращает MYFILE.txt
Разделить строку на регулярное выражение
Используйте
re.split (шаблон, строка)
. Возвращает список совпавших строк.Пример шаблона: разделить строку пробелами или запятыми
импорт ре re.split ('[\ s,] +', 'foo, bar bar quux') # ['foo', 'bar', 'bar', 'quux']
Разделить строку по границе слова
Вы не можете использовать
re.split (r '\ b', ...)
, потому что Python будет жаловаться:split () требует непустого сопоставления с шаблоном.
Используйте
findall (r '\ w +', . ..) вместо
:импорт ре # ValueError: split () требует непустого сопоставления с шаблоном. re.split (r '\ b', 'foo, bar bar-quux') # это то, что вы хотите: re.findall (r '\ w +', 'foo, bar bar-quux') # >>> ['foo', 'bar', 'bar', 'quux']
Группы без захвата
ШАБЛОН:
(?: ШАБЛОН)
Используйте группы без захвата, если вы хотите сопоставить что-то, что не просто состоит из символов (в противном случае вы бы просто использовали набор символов в квадратных скобках), и вам не нужно его захватывать.) foo (?: \ W | $) ‘
replace = «FOO»строка = ‘foo bar foo foofoo barfoobar foo’
re.sub (шаблон, замена, строка)
# >>> ‘FOO bar FOO foofoo barfoobar FOO’
Смотреть назад
ШАБЛОН:
(? <= ШАБЛОН)
Соответствует шаблону ТОЛЬКО, если НЕМЕДЛЕННО ПРЕДШЕСТВУЕТ .
Пример шаблона: "bar", только если ему предшествует "foo"
импорт ре # замените "bar" на "BAR", если ему предшествует "foo" pattern = "(? <= foo) bar" замена = "БАР" строка = "foo bar foobar" ре.sub (шаблон, замена, строка) # 'foo bar fooBAR'
Отрицательный взгляд назад
ШАБЛОН:
(?
Соответствует шаблону, если НЕ СРАЗУ ПРЕДШЕСТВУЕТ .
Пример шаблона: "bar", если ему НЕ предшествует "foo"
импорт ре # замените "bar" на BAR, если ему НЕ предшествует "foo" pattern = "(?
Просмотр вперед
ШАБЛОН:
(? = ШАБЛОН)
Шаблон соответствия, если он НЕМЕДЛЕННО СЛЕДУЕТ за чем-то другим.
Пример шаблона: «foo», только если за ним следует «bar»
импорт ре # замените "foo", только если за ним следует "bar" pattern = "foo (? = bar)" replace = "FOO" строка = "foo bar foobar" re.sub (шаблон, замена, строка) # 'foo bar fooBAR'
Отрицательный взгляд вперед
ШАБЛОН:
(?! ШАБЛОН)
Шаблон соответствия, если он НЕМЕДЛЕННО НЕ СЛЕДУЕТ за чем-то другим.
Пример шаблона: «foo», только если за ним НЕ следует «bar»
импорт ре # замените "foo", только если за ним НЕ следует "bar" pattern = "foo (?! bar)" replace = "FOO" строка = "foo bar foobar" re.sub (шаблон, замена, строка) # 'FOO bar foobar'
re.match VS re.search
повторное сопоставление (узор, строка) re.search (узор, строка) шаблон
должен соответствовать , начало
строка или ничего нешаблон
может быть где угодно в строке , но
возвращается только первое совпадение.re.match
соответствует , начало строки,re.search
соответствует шаблону один раз в любом месте строкиимпорт ре # возвращает None, нет совпадения re.match ('abc', 'xx abc xx') # Никто # возвращаем одно ПОИСКПОЗ re.match ('abc', 'abc') # <_sre.SRE_Match объект; span = (0, 3), match = 'abc'> ## возвращает одно ПОИСКПОЗ re.search ('abc', 'xx abc xx') # <_sre.SRE_Match объект; span = (3, 6), match = 'abc'> # по-прежнему возвращает одно ПОИСКПОЗ, даже если шаблон встречается более одного раза ре.поиск ('abc', 'xx abc xx abc') # <_sre.SRE_Match объект; span = (3, 6), match = 'abc'>
re.findall VS re.finditer
re.findall (узор, текст) re.finditer (узор, текст) Возвращает (возможно, пустой) список
изстроки
s, где регулярное выражение
нашло совпадение в строкеВозвращает (возможно, пустой) список
изобъектов Match
, содержащий совпадающий текст
, а также начальные
и конечные позиции, где было
совпаденийРегулярное выражение без учета регистра
Чтобы сделать ваши регулярные выражения нечувствительными к регистру Просто добавьте
(? I)
перед строкой шаблона. foo. * "," foo ")
Шпаргалка по регулярным выражениям Python и примеры
Визуализация выше представляет собой снимок экрана, созданный с помощью debuggex для шаблона
r '\ bpar (en | ro)? T \ b'
Из docs.python: re:
Регулярное выражение (или RE) определяет набор строк, который ему соответствует; функции в этом модуле позволяют проверить, соответствует ли конкретная строка заданному регулярному выражению
В этом сообщении блога дается обзор и примеры синтаксиса регулярных выражений, реализованного встроенным модулем
re
(Python 3.ограничивает соответствие до начала строки $
ограничивает соответствие до конца строки \ n
символ новой строки используется как разделитель строк re.
,$
и\
являются метасимволами в приведенной выше таблице, так как эти символы имеют специальные смысл. вместо якоря.Элемент Описание |
несколько RE объединены как условное ИЛИ каждая альтернатива может иметь независимые якоря (RE)
групповой шаблон (ы), а также группа захвата a (b | c) d
совпадает сabd | acd
(?: RE)
группа без захвата (? P
pat) группа захвата с именем .
Соответствует любому символу, кроме символа новой строки \ n
[]
Класс символов, соответствует одному символу из многих Жадные квантификаторы Описание *
Нулевое или более совпадение +
Одно или несколько совпадений ?
Нулевое или однократное совпадение {m, n}
Соответствие м от
доn
раз (включительно){m,}
Соответствие не менее m раз {, n}
Соответствие до n
раз (включая0
раз){n}
Совпадение ровно n раз pat1. * pat2
любое количество символов от pat1
доpat2
pat1. * pat2 | pat2. * pat1
соответствует как pat1
иpat2
в любом порядкеЖадный здесь означает, что приведенные выше квантификаторы будут соответствовать в максимально возможной степени, что также будет учитывать общий RE. Добавляя
?
для жадных квантификаторов делает их нежадными , то есть соответствует как минимум насколько возможно.\ s]Поисковые запросы Описание поисковые запросы настраиваемые утверждения, нулевые значения ширины, такие как анкеры (?! patser)
как отрицательный вид
(?
утверждение отрицательного просмотра назад (? = Pat)
утверждение положительного просмотра вперед (? <= Pat)
утверждение положительного просмотра назад (?! Pat1) (? = Pat2)
несколько утверждений могут быть указаны в любом порядке , поскольку они отмечают совпадающее местоположение без использования символов ((?! Pat) . ) *
Отменить группировку, аналогично инвертированному классу символов Флаги Описание re.IGNORECASE
илиre.I
флаг для игнорирования регистра
re.DOTALL
илиre.S
допускает .
метасимвол для соответствия символу новой строкиflags = re.S | re.I
несколько флагов могут быть объединены с помощью |
операторр.
иЯкоря
$ для соответствия по строкеre.VERBOSE
илиre.X
позволяет использовать буквальные пробелы для целей выравнивания и добавлять комментарии после символа #
escape-пробелы и #
при необходимости как часть фактического REre. ASCII
илиre.A
соответствуют только символам ASCII для \ b
,\ w
,\ d
,\ s
и их противоположности, применимые только для шаблонов Unicode re.LOCALE
илиre.L
использовать настройки локали для байтовых шаблонов и 8-битных локалей (? #Comment)
другой способ добавления комментариев, а не флаг (? flags: pat)
встроенные флаги только для этого pat
, отменяетflags
аргументflags is i
дляre.I
,s
дляre.S
и т. д. кромеL
дляre.L
(? -Flags: pat)
инвертировать флаги только для этого pat
(? Flags-flags: pat)
применять и отрицать определенные флаги только для этого pat
(? flags)
применить флаги для всего RE, может использоваться только в начале RE якоря, если они есть, следует указывать после (? flags)
Соответствующая часть Описание re. Сопоставить объект
детали, такие как сопоставленные части, местоположение и т. Д. м [0]
илим. Группа (0)
вся сопоставленная часть повторно сопоставить объект
м
m [n]
илим. Группа (n)
согласованная часть n -я группа захвата м. Группы ()
кортеж из согласованных частей всех групп захвата г.span ()
начало и конец + 1 индекс всей согласованной части передать число для получения диапазона этой конкретной группы захвата также можно использовать m.start ()
иm .end ()
\ N
обратная ссылка, дает согласованную часть N -я группа захвата применяется как к разделу поиска, так и к разделу замены возможные значения: \ 1
,\ 2
до\ 99
при условии отсутствия цифр\ g
обратная ссылка
, дает согласованную часть N-й группы захвата возможные значения: \ g < 0>
,\ g <1>
и т. Д. (Не ограничивается 99)\ g <0>
относится ко всей согласованной части(? P
pat) названная группа захвата см. «имя»
вre.Сопоставить объект
сослаться на (? P = name)
в разделе поискасослаться на \ g
в разделе заменыgroupdict
метод применен к a re.Match
объектдает именованные части группы захвата как dict
\ 0
и\ 100
и далее рассматриваются как восьмеричные значения, поэтому не могут использоваться в качестве обратных ссылок.re функции модуля🔗
Функция Описание re. search
Проверить, присутствует ли данный шаблон где-либо во входной строке Выход - это объект re.Match
, используемый в условных выраженияхr-строки, предпочтительные для определения RE Использовать байтовый шаблон для ввода байтов Python также поддерживает небольшой кеш последнего RE re.fullmatch
гарантирует, что шаблон соответствует всей входной строке re.compile
Скомпилирует шаблон для повторного использования, выводит re.Pattern
объектre.sub
поиск и замена re.sub (r'pat ', f, s)
функция f
сre.Match
объект в качестве аргументаre.escape
автоматически экранировать все метасимволы re. split
разделить строку на основе RE текст, соответствующий группам, будет частью вывода часть, соответствующая шаблону вне группы, не будет в выводе re. findall
возвращает все совпадения в виде списка если используется 1 группа захвата, возвращаются только ее совпадения 1+, каждый элемент будет кортежем групп захвата часть соответствует шаблону вне группы не будет на выходе re.finditer
итератор с объектом re.Match
для каждого совпаденияre.subn
дает кортеж измененной строки и количество замен Определения функций приведены ниже:
re.search (шаблон, строка, флаги = 0) re.fullmatch (шаблон, строка, флаги = 0) re.compile (шаблон, флаги = 0) re. sub (шаблон, repl, строка, count = 0, flags = 0) re.escape (шаблон) re.split (шаблон, строка, maxsplit = 0, flags = 0) ре.findall (шаблон, строка, флаги = 0) re.finditer (шаблон, строка, флаги = 0) re.subn (шаблон, repl, строка, count = 0, flags = 0)
Примеры регулярных выражений🔗
Рекомендуется всегда использовать необработанных строк для создания RE, если не требуются другие форматы. Это позволит избежать столкновения специального значения символа обратной косой черты между RE и обычными строками в кавычках.
>>> предложение = 'Это образец строки' # перед использованием необходимо загрузить модуль re >>> импорт ре # проверяем, содержит ли 'предложение' шаблон, описанный аргументом RE >>> bool (re.поиск (r'is ', предложение)) Правда # игнорировать регистр при поиске совпадения >>> bool (re.search (r'this ', предложение, flags = re.I)) Правда >>> bool (re.search (r'xyz ', предложение)) Ложь # вывод re.search можно напрямую использовать в условных выражениях >>> если re. search (r'ring ', предложение): ... print ('успех миссии') ... Миссия пройдена успешно # использовать необработанные байтовые строки, если входные данные имеют байтовый тип >>> bool (re.search (rb'is ', b'This is a sample string')) Правда
- Разница между анкерами для струн и строп
# анкеры для струн >>> bool (re.par $ ',' запасной \ npar \ ndare ', flags = re.M)) Правда
# целое слово par с необязательным s в начале и необязательным e в конце >>> re.findall (r '\ bs? pare? \ b', 'par spar очевидная запасная часть pare') ['par', 'spar', 'spare', 'pare'] # числа> = 100 с необязательными ведущими нулями >>> re.findall (r '\ b0 * [1-9] \ d {2,} \ b', '0501 035 154 12 26 98234') ['0501', '154', '98234'] # если используется несколько групп захвата, каждый элемент вывода # будет кортежем строк всех групп захвата >>> ре./,] +),? ',' 2020 / 04,1986 / Март ') [('2020', '04'), ('1986', 'март')] # обычная группа захвата помешает получить весь матч # группа без захвата спешит на помощь >>> re. findall (r '\ b \ w * (?: st | in) \ b', 'дороже на восток') ['стоимость', 'родственный', 'восток'] # полезно также для отладки >>> re.findall (r't. *? a ',' это выдумка ') ['tha', 't is a', 'ted ta']
# разделение на основе одного или нескольких цифровых символов >>> re.split (r '\ d +', 'Sample123string42with777numbers') ['Образец', 'строка', 'с', 'числами'] # разделение на основе цифр или пробелов >>> ре.разделить (r '[\ d \ s] +', '** 1 \ f2 \ n3star \ t7 77 \ r **') ['**', 'звезда', '**'] # чтобы включить соответствующие строки разделителей в вывод >>> re.split (r '(\ d +)', 'Sample123string42with777numbers') ["Образец", "123", "строка", "42", "с", "777", "числа"] # использовать группу без захвата, если захват не требуется >>> re.split (r'hand (?: y | ful) ',' 123handed42handy777handful500 ') ['123handed42', '777', '500']
- обратная ссылка в шаблоне поиска
# целые слова, содержащие хотя бы один повторяющийся символ подряд >>> words = ['усилия', 'бегство', 'фасад', 'чудак', 'крыса', 'инструмент'] >>> [w вместо w прописью, если re. поиск (r '\ b \ w * (\ w) \ 1 \ w * \ b', w)] ["усилие", "бегство", "чудак", "инструмент"]
- работа с согласованными порциями
>>> re.search (r'b. * D ',' abc ac adc abbbc ') <объект re.Match; span = (1, 9), match = 'bc ac ad'> # получение всей совпавшей части, обратите внимание на использование [0] >>> re.search (r'b. * d ',' abc ac adc abbbc ') [0] 'bc ac ad' # пример группы захвата >>> m = re.search (r'a (. *) d (. * a) ',' abc ac adc abbbc ') # чтобы получить совпавшую часть второй группы захвата >>> м [2] 'c a' # чтобы получить кортеж всех групп захвата >>> м.группы () ('bc ac a', 'c a')
# числа <350 >>> m_iter = re.finditer (r '[0-9] +', '45 349 651 593 4 204 ') >>> [m [0] вместо m в m_iter, если int (m [0]) <350] ['45', '349', '4', '204'] # начало и конец + 1 индекс каждой совпадающей части >>> m_iter = re.finditer (r'ab + c ',' abc ac adc abbbc ') >>> для m в m_iter: ... печать (m.span ()) ... (0, 3) (11, 16)
>>> ip_lines = "катапульты \ nconcatenate \ ncat" >>> print (re. :] +:) {2} ', r' ',' foo: 123: bar: baz ', count = 1) 'бар: баз'
- обратная ссылка в разделе замены
# удалить последовательные повторяющиеся слова, разделенные пробелом >>> re.sub (r '\ b (\ w +) (\ 1) + \ b', r '\ 1', 'aa a a a 42 f_1 f_1 f_13.14') 'aa a 42 f_1 f_13.14' # добавляем что-нибудь вокруг совпадающих строк >>> re.sub (r '\ d +', r '(\ g <0> 0)', '52 яблока и 31 манго ') '(520) яблок и (310) манго' # меняем местами слова, разделенные запятой >>> ре.sub (r '(\ w +), (\ w +)', r '\ 2, \ 1', 'хорошо, плохо 42,24') 'плохо, хорошо 24,42'
- с использованием функций в разделе замены
re.sub
>>> из математического импорта факториала >>> числа = '1 2 3 4 5' >>> def fact_num (n): ... return str (factorial (int (n [0]))) ... >>> re.sub (r '\ d +', fact_num, числа) '1 2 6 24 120' # используя лямбда >>> re.sub (r '\ d +', лямбда m: str (factorial (int (m [0]))), числа) '1 2 6 24 120'
# изменяйте 'foo', только если за ним не следует цифра # обратите внимание, что конец строки удовлетворяет заданному утверждению # foofoo имеет 2 совпадения, поскольку утверждение не использует символы >>> ре. sub (r'foo (?! \ d) ', r'baz', 'эй, еда! foo42 foot5 foofoo') Эй, базд! foo42 bazt5 bazbaz ' # изменить слово целиком, только если ему не предшествует: или - >>> re.sub (r '(? >> re.findall (r '(? <= -) \ d + (? = [:;])', 'fo-5, ba3; x-83, y-20: f12') ['20'] # слова, содержащие 'b', 'e' и 't' в любом порядке >>> words = ['секвойя', 'сомнительный', 'экспонат', 'уравнение'] >>> [w вместо w прописью, если re.search (r '(? =. * b) (? =. * e). * t', w)] ['сомнительно', 'выставлять'] # совпадение, если между at и par нет 'do' >>> bool (re.search (r'at ((?! do).) * par ',' лиса, кошка, собака, попугай ')) Ложь # совпадение, если между at и par нет 'go' >>> bool (re.search (r'at ((?! go).) * par ',' лиса, кошка, собака, попугай ')) Правда
Регулярные выражения могут быть скомпилированы с использованием функции
re. compile
, которая возвращает объектre.Pattern
. Все функции модуля верхнего уровняи
доступны как методы для этого объекта.Компиляция регулярного выражения помогает, если RE необходимо использовать в нескольких местах или вызывать несколько раз внутри цикла (преимущество в скорости). По умолчанию Python поддерживает небольшой список недавно использованных RE, поэтому выигрыш в скорости не распространяется на тривиальные варианты использования.>>> pet = re.compile (r'dog ') >>> тип (питомец) <класс 're.Pattern'> >>> bool (pet.search ('Они купили собаку')) Правда >>> bool (pet.search ('Кошка перешла им дорогу')) Ложь >>> pat = re.)] * \) ') >>> pat.sub ('', 'a + b (сложение) - foo () + c% d (#modulo)') 'a + b - foo + c% d' >>> pat.sub ('', 'Привет (привет). Хороший день (a (b)') 'Всем привет. Хороший день'
Python re (gex)? книга🔗
Посетите мой репозиторий Python re (gex)? для получения подробной информации о книге, которую я написал о регулярных выражениях Python. В электронной книге используется множество примеров для объяснения концепций с самого начала и шаг за шагом вводятся более сложные концепции. В книге также рассматривается регулярное выражение стороннего модуля.Шпаргалка и примеры, представленные в этом посте, основаны на содержании этой книги.
Воспользуйтесь этой ссылкой на Leanpub по сниженной цене.
регулярное выражение · PyPI
Дополнительные возможности
Номера проблем относятся к системе отслеживания ошибок Python, за исключением случаев, когда они указаны как «Проблема с Hg».
Добавлена поддержка поиска по условному шаблону (выпуск Hg 163)
Теперь проверка условного шаблона может быть поиском.
Примеры:
>>> регулярное выражение.match (г '(? (? = \ d) \ d + | \ w +)', '123abc') <объект regex.Match; span = (0, 3), match = '123'> >>> regex.match (r '(? (? = \ d) \ d + | \ w +)', 'abc123') <объект regex.Match; span = (0, 6), match = 'abc123'>
Это не совсем то же самое, что поиск в первой ветви пары альтернатив.
Примеры:
>>> print (regex.match (r '(?: (? = \ D) \ d + \ b | \ w +)', '123abc')) <объект regex.Match; span = (0, 6), match = '123abc'> >>> print (regex.match (r '(? (? = \ d) \ d + \ b | \ w +)', '123abc')) Никто
В первом примере поиск совпал, но оставшаяся часть первой ветви не совпала, поэтому была предпринята попытка второй ветви, тогда как во втором примере поиск совпадал, и первая ветвь не соответствовала, но вторая ветка была , а не попыток.
Добавлено соответствие POSIX (крайнее левое) (Hg issue 150)
Стандарт POSIX для регулярных выражений - возвращать самое левое совпадение. Это можно включить с помощью флага POSIX ((? P)).
Примеры:
>>> # Нормальное соответствие. >>> regex.search (r'Mr | Mrs ',' Mrs ') <объект regex.Match; span = (0, 2), match = 'Мистер'> >>> regex.search (r'one (сам)? (самодостаточный)? ',' самодостаточный ') <объект regex.Match; span = (0, 7), match = 'сам'> >>> # Соответствие POSIX. >>> regex.search (r '(? p) Mr | Mrs', 'Mrs') <объект regex.Match; span = (0, 3), match = 'Миссис'> >>> regex.search (r '(? p) one (self)? (самодостаточный)?', 'самодостаточный') <объект regex.Match; span = (0, 17), match = 'самодостаточно'>
Обратите внимание, что поиск совпадений займет больше времени, потому что, когда он находит совпадение в определенной позиции, он не возвращает его немедленно, а будет продолжать искать, есть ли там другое более длинное совпадение.
Добавлен (? (DEFINE)...) (Hg выпуск 152)
Если группы под названием «DEFINE» нет, то… будет проигнорировано, но любые определения группы в ней будут доступны.
Примеры:
>>> regex.search (r '(? (DEFINE) (? P
\ d +) (? P - \ w +)) (? & Quant) (? & Item)', '5 слонов') <объект regex.Match; span = (0, 11), match = '5 слонов'>
Добавлены (* PRUNE), (* SKIP) и (* FAIL) (Hg issue 153)
(* PRUNE) отбрасывает информацию об обратном отслеживании до этого момента. При использовании в атомарной группе или при поиске это не повлияет на ограничивающий шаблон.
(* SKIP) похож на (* PRUNE), за исключением того, что он также устанавливает, где в тексте начнется следующая попытка сопоставления. При использовании в атомарной группе или при поиске это не повлияет на ограничивающий шаблон.
(* FAIL) вызывает немедленный возврат. (* F) - разрешенное сокращение.
Добавлен \ K (Hg issue 151)
Сохраняет часть всего совпадения после позиции, в которой произошло \ K; часть до того, как она будет выброшена.
Не влияет на то, какие группы захвата возвращаются.
Примеры:
>>> m = regex.search (r '(\ w \ w \ K \ w \ w \ w)', 'abcdef') >>> м [0] 'cde' >>> м [1] 'abcde' >>> >>> m = regex.search (r '(? r) (\ w \ w \ K \ w \ w \ w)', 'abcdef') >>> м [0] 'до н.э' >>> м [1] 'bcdef'
Добавлен индекс захвата для expandf и subf / subfn (Hg issue 133)
Теперь вы можете использовать индексирование, чтобы получить захваты повторяющейся группы захвата.
Примеры:
>>> m = regex.match (r "(\ w) +", "abc") >>> m.expandf ("{1}") 'c' >>> m.expandf ("{1 [0]} {1 [1]} {1 [2]}") 'а б в' >>> m.expandf ("{1 [-1]} {1 [-2]} {1 [-3]}") 'c b a' >>> >>> m = regex.match (r "(? P <буква> \ w) +", "abc") >>> m.expandf ("{письмо}") 'c' >>> m.expandf ("{буква [0]} {буква [1]} {буква [2]}") 'а б в' >>> m.expandf ("{буква [-1]} {буква [-2]} {буква [-3]}") 'c b a'
Добавлена поддержка ссылки на группу по номеру с помощью (? P =...).
Это дополнение к существующему \ g <...>.
Исправлена обработка регулярных выражений, зависящих от языкового стандарта.
Флаг LOCALE предназначен для устаревшего кода и имеет ограниченную поддержку. Вам по-прежнему рекомендуется использовать Unicode.
Добавлены частичные совпадения (выпуск 102 Hg)
Частичное совпадение - это совпадение до конца строки, но эта строка была усечена, и вы хотите знать, возможно ли полное совпадение, если бы строка не была усечена.
Частичные совпадения поддерживаются методами совпадения, поиска, полного совпадения и средства поиска с аргументом частичного ключевого слова.
Объекты Match имеют частичный атрибут, который имеет значение True, если это частичное совпадение.
Например, если вы хотите, чтобы пользователь ввел 4-значное число и посимвольно проверял его по мере ввода:
>>> шаблон = regex.compile (r '\ d {4}') >>> # Изначально ничего не вводилось: >>> print (pattern.fullmatch ('', partial = True)) <регулярное выражение.Соответствующий объект; span = (0, 0), match = '', partial = True> >>> # Пустая строка - это нормально, но это только частичное совпадение. >>> # Пользователь вводит письмо: >>> print (pattern.fullmatch ('a', partial = True)) Никто >>> # Это никогда не совпадет. >>> # Пользователь удаляет это и вводит цифру: >>> print (pattern.fullmatch ('1', partial = True)) <объект regex.Match; span = (0, 1), match = '1', partial = True> >>> # Совпадает так далеко, но это только частичное совпадение. >>> # Пользователь вводит еще 2 цифры: >>> print (pattern.fullmatch ('123', partial = True)) <объект regex.Match; span = (0, 3), match = '123', partial = True> >>> # Совпадает так далеко, но это только частичное совпадение. >>> # Пользователь вводит еще одну цифру: >>> print (pattern.fullmatch ('1234', partial = True)) <объект regex.Match; span = (0, 4), match = '1234'> >>> # Это полный матч. >>> # Если пользователь вводит другую цифру: >>> print (pattern.fullmatch ('12345', частичное = Истина)) Никто >>> # Это уже не совпадение. >>> # Это частичное совпадение: >>> pattern.match ('123', partial = True) .partial Правда >>> # Это полное совпадение: >>> pattern.match ('1233', partial = True) .partial Ложь
* оператор некорректно работает с sub () (проблема 106 Hg)
Иногда непонятно, как следует обрабатывать совпадения нулевой ширины. Например, должен ли. * Соответствовать 0 символам сразу после сопоставления> 0 символов?
Примеры:
# Python 3. 7 и позже >>> regex.sub ('. *', 'x', 'test') 'xx' >>> regex.sub ('. *?', '|', 'тест') '|||||||||' # Python 3.6 и ранее >>> regex.sub ('(? V0). *', 'x', 'test') 'Икс' >>> regex.sub ('(? V1). *', 'x', 'test') 'xx' >>> regex.sub ('(? V0). *?', '|', 'test') '| t | e | s | t |' >>> regex.sub ('(? V1). *?', '|', 'тест') '|||||||||'
Добавлен capturesdict (Hg issue 86)
capturesdict - это комбинация groupdict и захватов:
groupdict возвращает dict названных групп и последний захват этих групп.
захватов возвращает список всех захватов группы
capturesdict возвращает список именованных групп и списки всех захватов этих групп.
Примеры:
>>> m = regex.match (r "(? :(? P
\ w +) (? P \ d +) \ n) +", "one 1 \ ntwo 2 \ nthree 3 \ n ") >>> m.groupdict () {'слово': 'три', 'цифры': '3'} >>> m.captures ("слово") ['один два три'] >>> m.captures ("цифры") ['1', '2', '3'] >>> м.capturesdict () {'слово': ['один', 'два', 'три'], 'цифры': ['1', '2', '3']} Разрешить повторяющиеся имена групп (Hg issue 87)
Имена групп теперь могут дублироваться.
Примеры:
>>> # С дополнительными группами: >>> >>> # Обе группы захватывают, второй захват "перезаписывает" первую. >>> m = regex.match (r "(? P
- \ w +)? or (? P
- \ w +)?", "первый или второй") >>> m.group ("элемент") 'второй' >>> м.захватывает ("предмет") ['первая секунда'] >>> # Только вторая группа захватывает. >>> m = regex.match (r "(? P
- \ w +)? or (? P
- \ w +)?", "или второй") >>> m.group ("элемент") 'второй' >>> m.captures ("элемент") ['второй'] >>> # Только первая группа захватывает. >>> m = regex.match (r "(? P
- \ w +)? or (? P
- \ w +)?", "first or") >>> m.group ("элемент") 'первый' >>> m.captures ("элемент") ['первый'] >>> >>> # С обязательными группами: >>> >>> # Обе группы захватывают, второй захват "перезаписывает" первую.>>> m = regex.match (r "(? P
- \ w *) или (? P
- \ w *)?", "первый или второй") >>> m.group ("элемент") 'второй' >>> m.captures ("элемент") ['первая секунда'] >>> # Опять обе группы захватывают, второй захват "перезаписывает" первую. >>> m = regex.match (r "(? P
- \ w *) or (? P
- \ w *)", "or second") >>> m.group ("элемент") 'второй' >>> m.captures ("элемент") ['', 'второй'] >>> # И снова обе группы захватывают, второй захват "перезаписывает" первую.>>> m = regex.match (r "(? P
- \ w *) or (? P
- \ w *)", "first or") >>> m.group ("элемент") '' >>> m.captures ("элемент") ['первый', '']
Добавлен фуллматч (issue # 16203)
fullmatch ведет себя как match, за исключением того, что он должен соответствовать всей строке.
Примеры:
>>> print (regex.fullmatch (r "abc", "abc"). Span ()) (0, 3) >>> print (regex.fullmatch (r "abc", "abcx")) Никто >>> print (regex.fullmatch (r "abc", "abcx", endpos = 3).промежуток ()) (0, 3) >>> print (regex.fullmatch (r "abc", "xabcy", pos = 1, endpos = 4) .span ()) (1, 4) >>> >>> regex.match (r "a. *?", "abcd"). group (0) 'а' >>> regex.fullmatch (r "a. *?", "abcd"). group (0) 'abcd'
Добавлены подпрограммы и подпрограммы
subf и subfn являются альтернативами sub и subn соответственно. При передаче строки замены они рассматривают ее как строку формата.
Примеры:
>>> regex.subf (r "(\ w +) (\ w +)", "{0} => {2} {1}", "foo bar") 'foo bar => bar foo' >>> регулярное выражение.subf (r "(? P
\ w +) (? P \ w +)", "{word2} {word1}", "foo bar") 'bar foo' Добавлено расширение для соответствия объекту
expandf - альтернатива расширению. При передаче заменяющей строки он обрабатывает ее как строку формата.
Примеры:
>>> m = regex.match (r "(\ w +) (\ w +)", "foo bar") >>> m.expandf ("{0} => {2} {1}") 'foo bar => bar foo' >>> >>> m = regex.match (r "(? P
\ w +) (? P \ w +)", "foo bar") >>> м.expandf ("{слово2} {слово1}") 'bar foo' Отключить искомую строку
Объект соответствия содержит ссылку на искомую строку через свой строковый атрибут. Метод detach_string «отсоединит» эту строку, делая ее доступной для сборки мусора, что может сэкономить ценную память, если эта строка очень большая.
Пример:
>>> m = regex.search (r "\ w +", "Привет, мир") >>> печать (m.group ()) Здравствуйте >>> print (m.string) Привет мир >>> м.detach_string () >>> печать (m.group ()) Здравствуйте >>> print (m.string) Никто
Рекурсивные шаблоны (Hg, выпуск 27)
Поддерживаются рекурсивные и повторяющиеся шаблоны.
(? R) или (? 0) пытается рекурсивно сопоставить все регулярное выражение. (? 1), (? 2) и т. Д. Попробуйте сопоставить соответствующую группу захвата.
(? & Name) пытается сопоставить названную группу захвата.
Примеры:
>>> regex.match (r "(Тарзан | Джейн) любит (? 1)", "Тарзан любит Джейн").группы () ('Тарзан',) >>> regex.match (r "(Тарзан | Джейн) любит (? 1)", "Джейн любит Тарзана"). groups () ('Джейн',) >>> m = regex.search (r "(\ w) (? :(? R) | (\ w?)) \ 1", "kayak") >>> m.group (0, 1, 2) ('каяк', 'к', нет)
Первые два примера показывают, как повторно используется подшаблон в группе захвата, но сам _не_ не является группой захвата. Другими словами, «(Тарзан | Джейн) любит (? 1)» эквивалентно «(Тарзан | Джейн) любит (?: Тарзан | Джейн)».
Можно вернуться в повторяющуюся или повторяющуюся группу.
Вы не можете позвонить в группу, если существует более одной группы с таким названием или номером группы («неоднозначная ссылка на группу»).
Альтернативные формы (? P> name) и (? P & name) также поддерживаются.
Поддерживается полное сворачивание регистра Unicode.
В поведении версии 1 модуль регулярных выражений использует полное сворачивание регистра при выполнении совпадений без учета регистра в Unicode.
Примеры (в Python 3):
>>> regex.match (r "(? IV1) strasse", "stra \ N {LATIN SMALL LETTER SHARP S} e").промежуток () (0, 6) >>> regex.match (r "(? iV1) stra \ N {LATIN SMALL LETTER SHARP S} e", "STRASSE"). span () (0, 7)
В поведении версии 0 используется простое сворачивание регистра для обратной совместимости с модулем re.
Приблизительное «нечеткое» соответствие (выпуск Hg 12, выпуск 41 Hg, выпуск 109)
Regex обычно пытается найти точное совпадение, но иногда требуется приблизительное или «нечеткое» совпадение в тех случаях, когда искомый текст может содержать ошибки в виде вставленных, удаленных или замененных символов.
Нечеткое регулярное выражение определяет, какие типы ошибок разрешены, и, необязательно, минимальное и максимальное или только максимальное разрешенное количество каждого типа. (Вы не можете указать только минимум.)
3 типа ошибок:
- Вставка, обозначенная буквой «i»
- Удаление, обозначено буквой «d»
- Замена, обозначенная буквой s
Кроме того, «e» указывает на любой тип ошибки.
Нечеткость элемента регулярного выражения указывается между «{» и «}» после элемента.
Примеры:
- foo соответствует «foo» точно
- (?: Foo) {i} соответствует «foo», разрешая вставки
- (?: Foo) {d} соответствует «foo», разрешая удаление
- (?: Foo) {s} соответствует "foo", разрешая замены
- (?: Foo) {i, s} соответствует «foo», разрешая вставки и замены
- (?: Foo) {e} соответствует «foo», допускает ошибки
Если указан определенный тип ошибки, то любой неуказанный тип будет разрешен , а не .
В следующих примерах я опущу элемент и напишу только нечеткость:
- {d <= 3} разрешает не более 3 удалений, но не другие типы
- {i <= 1, s <= 2} разрешает не более 1 вставку и не более 2 замен, но не удаление
- {1 <= e <= 3} допускает от 1 до 3 ошибок
- {i <= 2, d <= 2, e <= 3} разрешает не более 2 вставок, не более 2 удалений, всего не более 3 ошибок, но без замен
Также можно указать стоимость каждого типа ошибки и максимально допустимую общую стоимость.
Примеры:
- {2i + 2d + 1s <= 4} каждая вставка стоит 2, каждое удаление стоит 2, каждая замена стоит 1, общая стоимость не должна превышать 4
- {i <= 1, d <= 1, s <= 1,2i + 2d + 1s <= 4} не более 1 вставки, не более 1 удаления, не более 1 замены; каждая вставка стоит 2, каждое удаление стоит 2, каждая замена стоит 1, общая стоимость не должна превышать 4
Вы также можете использовать «<» вместо «<=», если хотите исключительный минимум или максимум.
Вы можете добавить тест, который будет выполнять замену или вставку символа.
Примеры:
- {s <= 2: [a-z]} не более 2 замен, которые должны быть в наборе символов [a-z].
- {s <= 2, i <= 3: \ d} не более 2 замен, не более 3 вставок, которые должны быть цифрами.
По умолчанию, нечеткое совпадение ищет первое совпадение, которое удовлетворяет заданным ограничениям. Флаг ENHANCEMATCH заставит его попытаться улучшить соответствие (т.е.е. уменьшить количество ошибок) найденного совпадения.
Флаг BESTMATCH заставит вместо этого искать лучшее совпадение.
Другие примеры на заметку:
- regex.search ("(dog) {e}", "cat and dog") [1] возвращает "cat", потому что это соответствует "dog" с 3 ошибками (разрешено неограниченное количество ошибок).
- regex.search ("(dog) {e <= 1}", "cat and dog") [1] возвращает "dog" (с начальным пробелом), потому что это соответствует "dog" с 1 ошибкой, которая находится в пределах предел.
- regex.search ("(? E) (dog) {e <= 1}", "cat and dog") [1] возвращает "dog" (без начального пробела), потому что нечеткий поиск соответствует "dog" с 1. ошибка, которая находится в пределах лимита, и (? e), тогда он пытается лучше соответствовать.
В первых двух примерах есть более поздние совпадения в строке, но ни в том, ни в другом случае это не первое возможное совпадение.
У объекта соответствия есть атрибут fuzzy_counts, который дает общее количество замен, вставок и удалений.
>>> # Нечеткое совпадение: >>> regex.fullmatch (r "(?: cats | cat) {e <= 1}", "cat"). fuzzy_counts (0, 0, 1) >>> # 0 замен, 0 вставок, 1 удаление. >>> # Лучшее совпадение могло бы быть возможным, если бы использовался флаг ENHANCEMATCH: >>> regex.fullmatch (r "(? e) (?: cats | cat) {e <= 1}", "cat"). fuzzy_counts (0, 0, 0) >>> # 0 замен, 0 вставок, 0 удалений.
У объекта соответствия также есть атрибут fuzzy_changes, который дает кортеж позиций замен, вставок и удалений.
Итак, фактическая строка была:
'anaconda foo bar'
Именованные списки (Hg, выпуск 11)
\ L <имя>
Бывают случаи, когда вы можете захотеть включить список (фактически, набор) параметров в регулярное выражение.
Один из способов - построить такой шаблон:
>>> p = regex.compile (r "первый | второй | третий | четвертый | пятый")
, но если список большой, синтаксический анализ результирующего регулярного выражения может занять значительное время, и необходимо также позаботиться о том, чтобы строки были правильно экранированы и правильно упорядочены, например, «кошки» перед «кошкой».
Новая альтернатива - использовать именованный список:
>>> option_set = ["первый", "второй", "третий", "четвертый", "пятый"] >>> p = регулярное выражение.компиляция (r "\ L
", options = option_set) Порядок элементов не имеет значения, они рассматриваются как набор. Именованные списки доступны как атрибут. Named_lists объекта шаблона:
.
>>> печать (p. named_lists) # Python 3 {'options': frozenset ({'пятый', 'первый', 'четвертый', 'второй', 'третий'})} # Python 2 {'options': frozenset (['пятый', 'четвертый', 'второй', 'третий', 'первый'])}
Если есть неиспользуемые аргументы ключевого слова, ValueError будет вызвано, если вы не укажете иное:
>>> option_set = ["первый", "второй", "третий", "четвертый", "пятый"] >>> p = регулярное выражение.compile (r "\ L
", options = option_set, other_options = []) Отслеживание (последний вызов последний): Файл " ", строка 1, в Файл "C: \ Python37 \ lib \ site-packages \ regex \ regex.py", строка 348, в компиляции return _compile (шаблон, флаги, ignore_unused, kwargs) Файл "C: \ Python37 \ lib \ site-packages \ regex \ regex.py", строка 585, в _compile поднять ValueError ('неиспользуемый аргумент ключевого слова {! a}'. формат (any_one)) ValueError: неиспользуемый аргумент ключевого слова 'other_options' >>> p = регулярное выражение. компиляция (r "\ L ", options = option_set, other_options = [], ignore_unused = True) >>> Начало и конец слова
\ m соответствует началу слова.
\ M соответствует концу слова.
Сравните с \ b, которое соответствует началу или концу слова.
Разделители строк Unicode
Обычно единственным разделителем строк является \ n (\ x0A), но если флаг WORD включен, то разделителями строк являются \ x0D \ x0A, \ x0A, \ x0B, \ x0C и \ x0D, плюс \ x85, \ u2028 и \ u2029 при работе с Unicode.и $ (в многострочном режиме).
Установить операторы
Только поведение версии 1
Добавлены операторы множества, [...] набор может включать вложенные множества.
Операторы в порядке возрастания приоритета:
- || для объединения («x || y» означает «x или y»)
- ~~ (двойная тильда) для симметричной разницы («x ~~ y» означает «x или y, но не оба»)
- && для перекрестка («x && y» означает «x и y»)
- - (двойное тире) для разницы («x – y» означает «x, но не y»)
Неявное объединение, то есть простое сопоставление, как в [ab], имеет наивысший приоритет. Таким образом, [ab && cd] совпадает с [[a || b] && [c || d]].
Примеры:
- [ab] # Набор, содержащий «a» и «b»
- [a-z] # Набор, содержащий "a" .. "z"
- [[a-z] - [qw]] # Набор, содержащий «a» .. «z», но не «q» или «w»
- [a-z - qw] # То же, что и выше
- [\ p {L} - QW] # Набор, содержащий все буквы, кроме «Q» и «W»
- [\ p {N} - [0-9]] # Набор, содержащий все числа, кроме "0" .. "9"
- [\ p {ASCII} && \ p {Letter}] # Набор, содержащий все символы, которые являются ASCII и буквой
регулярное выражение.escape (issue # 2650)
regex.escape имеет дополнительный параметр ключевого слова special_only. Если True, экранируются только «специальные» символы регулярного выражения, такие как «?».
Примеры:
>>> regex.escape ("foo !?", special_only = False) 'foo \\! \\?' >>> regex.escape ("foo !?", special_only = True) 'foo! \\?'
regex.escape (Hg issue 249)
regex. escape имеет дополнительный параметр ключевого слова literal_spaces. Когда True, пробелы не экранируются.
Примеры:
>>> регулярное выражение.escape ("foo bar !?", literal_spaces = False) 'foo \\ bar! \\?' >>> regex.escape ("foo bar !?", literal_spaces = True) 'foo bar! \\?'
Повторные снимки (issue # 7132)
У объекта соответствия есть дополнительные методы, которые возвращают информацию обо всех успешных совпадениях повторяющейся группы захвата. Эти методы:
- matchobject.captures ([group1, ...])
- Возвращает список строк, сопоставленных в группе или группах. Сравните с matchobject.group ([group1,...]).
- matchobject.starts ([group])
- Возвращает список начальных позиций. Сравните с matchobject.start ([группа]).
- matchobject.ends ([группа])
- Возвращает список конечных позиций. Сравните с matchobject.end ([группа]).
- matchobject.spans ([group])
- Возвращает список диапазонов. Сравните с matchobject.span ([группа]).
Примеры:
>>> m = регулярное выражение.search (r "(\ w {3}) +", "123456789") >>> m.group (1) '789' >>> m.captures (1) ['123', '456', '789'] >>> m.start (1) 6 >>> m.starts (1) [0, 3, 6] >>> m.end (1) 9 >>> m.ends (1) [3, 6, 9] >>> м. пролет (1) (6, 9) >>> м. пролеты (1) [(0, 3), (3, 6), (6, 9)]
Атомная группировка (issue # 433030)
(?> ...)
Если следующий шаблон впоследствии не сработает, то подшаблон в целом выйдет из строя.
Притяжательные кванторы.
(?: ...)? +; (?: ...) * +; (?: ...) ++; (?: ...) {мин., макс.} +
Подшаблон сопоставляется до «максимального» раз. Если следующий шаблон впоследствии не сработает, то все повторяющиеся подшаблоны потерпят неудачу в целом. Например, (?: ...) ++ эквивалентно (?> (?: ...) +).
Флаги с ограничением (issue # 433028)
(? Флаги-флаги: ...)
Флаги будут применяться только к подшаблону. Флаги можно включить или выключить.
Определение символа «слово» (issue # 16
)
Определение символа «слово» было расширено для Unicode.Теперь он соответствует спецификации Unicode по адресу http://www.unicode.org/reports/tr29/.
Заглядывание назад переменной длины
Поиск назад может соответствовать строке переменной длины.
Флаги аргумента для regex.split, regex.sub и regex.subn (issue # 3482)
regex.split, regex.sub и regex.subn поддерживают аргумент «flags».
Аргументы Pos и endpos для regex.sub и regex.subn
regex.sub и regex.subn поддерживают аргументы «pos» и «endpos».
Аргумент «перекрывающийся» для regex.findall и regex.finditer
regex.findall и regex.finditer поддерживают флаг «перекрытия», который разрешает перекрывающиеся совпадения.
Сплиттер
Добавлен
regex.splititer. Это генератор, эквивалентный regex.split.
Подписка на группы
Объект сопоставления принимает доступ к захваченным группам через индексирование и нарезку:
>>> m = regex. search (r "(? P
.*?) (? P \ d +) (? P . *) "," Pqr123stu ") >>> print (m ["до"]) pqr >>> print (len (m)) 4 >>> print (m [:]) ('pqr123stu', 'pqr', '123', 'stu') Именованные группы
Группы могут быть названы как (?
...), так и текущими (? P ...). Групповые ссылки
На группы можно ссылаться в шаблоне с помощью \ g
. Это также позволяет иметь более 99 групп. Именованные персонажи
\ N {name}
Поддерживаются именованные символы.свойство = значение}.
Если используется краткая форма \ p {значение}, свойства проверяются в следующем порядке: General_Category, Script, Block, binary property:
- Latin, «латинский» шрифт (Script = Latin).
- BasicLatin, блок «BasicLatin» (блок = BasicLatin).
- Alphabetic, бинарное свойство «Alphabetic» (Alphabetic = Yes).
Краткая форма, начинающаяся с Is, указывает свойство скрипта или двоичного файла:
- IsLatin, «латинский» шрифт (Script = Latin). альфа:]]
Поддерживаются
классов символов POSIX. Обычно они рассматриваются как альтернативная форма \ p {...}.
Исключения составляют alnum, digit, punct и xdigit, определения которых отличаются от определений Unicode.
[[: alnum:]] эквивалентно \ p {posix_alnum}.
[[: digit:]] эквивалентно \ p {posix_digit}.
[[: punct:]] эквивалентно \ p {posix_punct}.
[[: xdigit:]] эквивалентно \ p {posix_xdigit}.
Поисковый якорь
\ G
Добавлен поисковый якорь.Он соответствует позиции, в которой каждый поиск начался / продолжался, и может использоваться для непрерывных совпадений или в отрицательных обратных просмотрах переменной длины, чтобы ограничить, насколько далеко назад идет ретроспективный поиск:
>>> regex.findall (r "\ w {2}", "abcd ef") ['ab', 'cd', 'ef'] >>> regex.findall (r "\ G \ w {2}", "abcd ef") ['ab', 'cd']
- Поиск начинается с позиции 0 и соответствует 2 буквам «ab».
- Поиск продолжается с позиции 2 и соответствует 2 буквам «cd».
- Поиск продолжается в позиции 4 и не может найти никаких букв.
- Якорь останавливает продвижение начальной позиции поиска, поэтому результатов больше нет.
Обратный поиск
Поиски теперь могут работать в обратном направлении:
>>> regex.findall (r ".", "Abc") ['a', 'b', 'c'] >>> regex.findall (r "(? r).", "abc") ['c', 'b', 'a']
Примечание: результат обратного поиска не обязательно является обратным результатом прямого поиска:
>>> regex.findall (r "..", "abcde") ['ab', 'cd'] >>> регулярное выражение.findall (r "(? r) ..", "abcde") ['de', 'bc']
Соответствие одной графемы
\ X
Поддерживается сопоставление графем. Теперь он соответствует спецификации Unicode по адресу http://www.unicode.org/reports/tr29/.
Сброс ответвления
(? | ... | ...)
Номера групп захвата будут повторно использоваться в альтернативах, но группы с разными именами будут иметь разные номера групп.
Примеры:
>>> regex.match (r "(? | (Первый) | (второй))", "первый").группы () ('первый',) >>> regex.match (r "(? | (первый) | (второй))", "второй"). groups () ('второй',)
Обратите внимание, что существует только одна группа.
Граница слова в Юникоде по умолчанию
Флаг WORD изменяет определение «границы слова» на определение границы слова Unicode по умолчанию. Это относится к \ b и \ B.
Тайм-аут (Python 3)
Методы и функции сопоставления поддерживают тайм-ауты. Тайм-аут (в секундах) применяется ко всей операции:
>>> из времени импорта сна >>> >>> def fast_replace (m): ... вернуть "X" ... >>> def slow_replace (m): ... сон (0,5) ... вернуть 'X' ... >>> regex.sub (r '[a-z]', fast_replace, 'abcde', timeout = 2) "XXXXX" >>> regex.sub (r '[a-z]', slow_replace, 'abcde', timeout = 2) Отслеживание (последний вызов последний): Файл "
", строка 1, в Файл "C: \ Python37 \ lib \ site-packages \ regex \ regex. py", строка 276, в подпрограмме endpos, concurrent, timeout) TimeoutError: истекло время ожидания регулярного выражения Использование регулярного выражения для обработки текста в Python
Введение
Предварительная обработка текста - одна из самых важных задач в обработке естественного языка (NLP).Например, вы можете удалить все знаки препинания из текстовых документов, прежде чем их можно будет использовать для классификации текста. Точно так же вы можете извлечь числа из текстовой строки. Написание ручных сценариев для таких задач предварительной обработки требует больших усилий и подвержено ошибкам. Принимая во внимание важность этих задач предварительной обработки, регулярные выражения (также известные как Regex) были разработаны на разных языках, чтобы упростить эти задачи предварительной обработки текста.
Регулярное выражение - это текстовая строка, описывающая шаблон поиска, который можно использовать для сопоставления или замены шаблонов внутри строки с минимальным количеством кода. В этом руководстве мы реализуем различные типы регулярных выражений на языке Python.
Для реализации регулярных выражений можно использовать пакет Python
re
. Импортируйте пакет Pythonre
с помощью следующей команды:импорт ре
Поиск шаблонов в строке
Одна из наиболее распространенных задач НЛП - поиск, содержит ли строка определенный шаблон или нет. Например, вы можете захотеть выполнить операцию со строкой при условии, что строка содержит число.
Для поиска шаблона в строке используется функция
match
иfindall
пакетаre
.Функция соответствия
Инициализировать переменную
текст
текстовой строкой, как показано ниже:text = "Фильм" Титаник "был выпущен в 1998 году"
Давайте напишем выражение регулярного выражения, которое соответствует строке любой длины и любого символа:
результат = re. match (r ". *", Текст)
Первый параметр функции
match
- это регулярное выражение, которое вы хотите найти.Выражение регулярного выражения начинается с алфавитаr
, за которым следует шаблон, который вы хотите найти. Образец следует заключать в одинарные или двойные кавычки, как и любую другую строку.Вышеприведенное выражение регулярного выражения будет соответствовать текстовой строке, поскольку мы пытаемся сопоставить строку любой длины и любого символа. Если совпадение найдено, функция
match
возвращает_sre.SRE_Match
объект, как показано ниже:тип (результат)
Выход:
_ср.SRE_Match
Теперь, чтобы найти совпадающую строку, вы можете использовать следующую команду:
result.group (0)
Выход:
'Фильм Титаник вышел в 1998 году'
В случае, если функция
match
не обнаружит соответствия, возвращается объектnull
.Теперь предыдущее выражение регулярного выражения соответствует строке любой длины и любого символа. Он также будет соответствовать пустой строке нулевой длины.Чтобы проверить это, обновите значение текстовой переменной пустой строкой:
text = ""
Теперь, если вы снова выполните следующее выражение регулярного выражения, совпадение будет найдено:
результат = re.match (r ". *", Текст)
Поскольку мы указали соответствие строки любой длины и любого символа, даже пустая строка будет сопоставлена.
Чтобы сопоставить строку длиной не менее 1, используется следующее выражение регулярного выражения:
результат = re.совпадение (г ". +", текст)
Здесь знак плюса указывает, что строка должна содержать как минимум один символ.
Поисковые алфавиты
Функция
match
может использоваться для поиска любых букв алфавита в строке. Давайте инициализируем текстовую переменную следующим текстом:text = "Фильм" Титаник "был выпущен в 1998 году"
Теперь, чтобы найти все буквы алфавита, как в верхнем, так и в нижнем регистре, мы можем использовать следующее выражение регулярного выражения:
результат = re. совпадение (r "[a-zA-z] +", текст)
Это регулярное выражение указывает, что текстовая строка соответствует любым алфавитам от маленького
a
до малогоz
или заглавногоA
до заглавногоZ
. Знак плюс указывает, что строка должна содержать хотя бы один символ. Напечатаем совпадение, найденное по приведенному выше выражению:печать (result.group (0))
Выход:
В выводе видно, что первое слово i.е.
Возвращен
. Это связано с тем, что функцияmatch
возвращает только первое найденное совпадение. В регулярном выражении мы указали, что находят шаблоны как с малым, так и с прописным алфавитом отдо
доz
. Первым найденным совпадением былоThe
. После словаОднако с этим есть проблема.Если строка начинается с числа, а не с алфавита, функция
match
вернет null, даже если после числа есть алфавиты. Посмотрим на это в действии:text = "1998 год стал годом выхода фильма" Титаник " результат = re.match (r "[a-zA-z] +", текст) тип (результат)
Выход:
NoneType
В приведенном выше скрипте мы обновили текстовую переменную, и теперь она начинается с цифры. Затем мы использовали функцию
match
для поиска алфавитов в строке.Хотя текстовая строка содержит алфавиты, будет возвращено значение null, посколькуmatch
функция соответствует только первому элементу в строке.Чтобы решить эту проблему, мы можем использовать функцию поиска
Функция поиска
Функция поиска
сопоставления
, т.е. она пытается сопоставить указанный шаблон. Однако, в отличие от функцииmatch
, она соответствует шаблону глобально, а не только первому элементу.Следовательно, функция поискаtext = "1998 год стал годом выхода фильма" Титаник " result = re.search (r "[a-zA-z] +", текст) печать (result.group (0))
Выход:
было
Функция поиска
print («Соответствие найдено»)
еще:
print («Соответствие не найдено»)
Выход:
Соответствие найдено
Соответствующие строки от конца
Чтобы проверить, заканчивается ли строка определенным словом или нет, мы можем использовать это слово в регулярном выражении, за которым следует знак доллара. Знак доллара отмечает конец заявления. Взгляните на следующий пример:
text = "1998 год стал годом выхода фильма" Титаник " если ре.поиск (r "1998 $", текст): print («Соответствие найдено») еще: print («Соответствие не найдено»)
В приведенном выше сценарии мы попытались определить, заканчивается ли текстовая строка на «1998», но это не так.
Выход:
Соответствие не найдено
Теперь, если мы обновим строку и добавим «1998» в конец текстовой строки, приведенный выше сценарий вернет «Соответствие найдено», как показано ниже:
text = "1998 год был годом выхода фильма" Титаник " если ре.поиск (r "1998 $", текст): print («Соответствие найдено») еще: print («Соответствие не найдено»)
Выход:
Соответствие найдено
Подстановка текста в строку
До сих пор мы использовали регулярное выражение, чтобы определить, существует ли шаблон в строке. Давайте продолжим с другой расширенной функцией регулярного выражения, то есть заменой текста в строке. Для этого используется функция
sub
.Давайте рассмотрим простой пример функции подстановки.Допустим, у нас есть следующая строка:
text = "Фильм" Криминальное чтиво "был выпущен в 1994 году"
Чтобы заменить строку «Криминальное чтиво» на «Форрест Гамп» (другой фильм, выпущенный в 1994 году), мы можем использовать функцию
sub
следующим образом:result = re.sub (r «Криминальное чтиво», «Форрест Гамп», текст)
Первым параметром функции
sub
является регулярное выражение, которое находит шаблон для замены. Второй параметр - это новый текст, который вы хотите заменить старым, а третий параметр - это текстовая строка, для которой будет выполняться операция замены.Если вы напечатаете переменную результата, вы увидите новую строку.
Теперь давайте заменим все алфавиты в нашей строке на символ «X». Выполните следующий скрипт:
text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" result = re.sub (r "[a-z]", "X", текст) печать (результат)
Выход:
TXX XXXX PXXX FXXXXXX XXX XXXXXXXX XX XXXX 1994
Из вывода видно, что заменены все символы, кроме заглавных.Это потому, что мы указали только
a-z
, а неA-Z
. Есть два способа решить эту проблему. Вы можете указатьA-Z
в регулярном выражении вместе сa-z
следующим образом:результат = re.sub (r "[a-zA-Z]", "X", текст)
Или вы можете передать дополнительный параметр
flags
в подфункцию и установить его значениеre.I
, которое относится к нечувствительности к регистру, следующим образом:результат = re.sub (r "[a-z]", "X", текст, flags = re.I)
Более подробную информацию о различных типах флагов можно найти на странице официальной документации Python regex.
Сокращенные классы символов
Существуют различные типы сокращенных классов символов, которые можно использовать для выполнения множества различных функций манипулирования строками без необходимости написания сложной логики. В этом разделе мы обсудим некоторые из них:
Удаление цифр из строки
Выражение регулярного выражения для поиска цифр в строке:
\ d
.Этот шаблон можно использовать для удаления цифр из строки путем замены их пустой строкой нулевой длины, как показано ниже:text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" result = re.sub (r "\ d", "", текст) печать (результат)
Выход:
Фильм Криминальное чтиво был выпущен в год
Удаление букв алфавита из строки
text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" результат = ре.sub (r "[a-z]", "", текст, flags = re.I) печать (результат)
Выход:
1994
Удаление символов слова
Если вы хотите удалить все символы слова (буквы и цифры) из строки и сохранить оставшиеся символы, вы можете использовать шаблон
\ w
в своем регулярном выражении и заменить его пустой строкой нулевой длины, как показано ниже. :text = "Фильм '@Pulp Fiction' был? Выпущен в% $ 1994 году." result = re.sub (r "\ w", "", text, flags = re.I) печать (результат)
Выход:
, '@'? % $.
Выходные данные показывают, что все числа и алфавиты были удалены.
Удаление символов, отличных от слов
Чтобы удалить все символы, не являющиеся словами, можно использовать шаблон
\ W
следующим образом:text = "Фильм '@Pulp Fiction' был? Выпущен в% $ 1994." результат = re.sub (r "\ W", "", текст, flags = re.Я) печать (результат)
Выход:
ФильмКриминальное чтиво вышел в прокат в 1994 году
Из вывода видно, что все было удалено (даже пробелы), кроме чисел и букв.
Группировка нескольких паттернов
Вы можете сгруппировать несколько шаблонов для сопоставления или замены в строке, используя квадратную скобку. Фактически, мы сделали это, сопоставив заглавные и строчные буквы. Сгруппируем несколько знаков препинания и удалим их из строки:
text = "Фильм '@Pulp Fiction' был? Выпущен _ в% $ 1994 году." result = re.sub (r "[, @ \ '? \. $% _]", "", text, flags = re.I) печать (результат)
Выход:
Фильм Криминальное чтиво был выпущен в 1994 году.
Вы можете видеть, что строка в текстовой переменной имела несколько знаков препинания, мы сгруппировали все эти знаки препинания в выражении регулярного выражения, используя квадратные скобки. Важно отметить, что с точкой и одинарной кавычкой мы должны использовать escape-последовательность, то есть обратную косую черту. Это связано с тем, что по умолчанию оператор точки используется для любого символа, а одинарная кавычка используется для обозначения строки.
Удаление нескольких пробелов
Иногда между словами появляется несколько пробелов в результате удаления слов или знаков препинания. Например, в выводе последнего примера есть несколько пробелов между
в
игоду
. Эти пробелы можно удалить, используя шаблон\ s
, который относится к одному пробелу.text = "Фильм" Криминальное чтиво "вышел в 1994 году." результат = re.sub (r "\ s +", "", текст, flags = re.Я) печать (результат)
Выход:
Фильм Криминальное чтиво вышел на экраны в 1994 году.
В приведенном выше скрипте мы использовали выражение
\ s +
, которое относится к одному или нескольким пробелам.Удаление пробелов в начале и в конце
Иногда у нас есть предложение, которое начинается или заканчивается пробелом, что часто нежелательно. Следующий скрипт удаляет пробелы в начале предложения:
text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" результат = ре.\ s + "," ", текст) печать (результат)
Выход:
Фильм Криминальное чтиво был выпущен в 1994 году.
Аналогично, чтобы удалить пробел в конце строки, можно использовать следующий скрипт:
text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" результат = re.sub (r "\ s + $", "", текст) печать (результат)
Удаление одного символа
Иногда удаление знаков препинания, например апострофа, приводит к появлению одного символа, не имеющего значения.Например, если вы удалите апостроф из слова
Jacob s
и замените его пробелом, получится строкаJacob s
. Здесьs
не имеет смысла. Такие одиночные символы можно удалить с помощью регулярного выражения, как показано ниже:text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" result = re.sub (r "\ s + [a-zA-Z] \ s +", "", текст) печать (результат)
Выход:
Фильм Криминальное чтиво был выпущен в 1994 году.
Скрипт заменяет любую строчную или заглавную букву между одним или несколькими пробелами на один пробел.
Разделение строки
Разделение строк - еще одна очень важная функция. Строки можно разделить с помощью функции
split
из пакета re. Функцияsplit
возвращает список токенов разделения. Давайте разделим строку слов, в которой найдены один или несколько пробелов, как показано ниже:text = "Фильм" Криминальное чтиво "был выпущен в 1994 году" результат = re.split (r "\ s +", текст) печать (результат)
Выход:
['The', 'film', 'Pulp', 'Fiction', 'was', 'выпущено', 'in', 'year', '1994', '']
Точно так же вы можете использовать другие выражения регулярных выражений для разделения строки с помощью функций
split
.Например, следующая функцияsplit
разбивает строку слов при обнаружении запятой:text = "Фильм« Криминальное чтиво »вышел в 1994 году» result = re.split (r "\,", текст) печать (результат)
Выход:
['Фильм', 'Криминальное чтиво', 'выпущен в 1994 году']
Поиск всех экземпляров
Функция
match
выполняет сопоставление первого элемента, в то время как функция поискаНапример, если у нас есть следующая строка:
text = "Я хочу купить мобильный за 200–400 евро"
Мы хотим найти все цифры в этой строке. Если мы используем функцию поиска
результат = re.search (r "\ d +", текст) печать (result.group (0))
Выход:
200
С другой стороны, функция
findall
возвращает список, содержащий все совпавшие высказывания, как показано ниже:text = "Я хочу купить мобильный за 200–400 евро" результат = ре.findall (r "\ d +", текст) печать (результат)
Выход:
['200', '400']
Из выходных данных видно, что и «200», и «400» возвращаются функцией
findall
.Заключение
В этой статье мы изучили некоторые из наиболее часто используемых функций регулярных выражений в Python.