Регулярные выражения в 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», метод вернет
:
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.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»
Функция findall — Документация Python для сетевых инженеров 3.
0Функция
findall()
:
- используется для поиска всех непересекающихся совпадений в шаблоне
- возвращает:
- список строк, которые описаны регулярным выражением, если в регулярном выражении нет групп
- список строк, которые совпали с регулярным выражением в группе, если в регулярном выражении одна группа
- список кортежей, в которых находятся строки, которые совпали с выражением в группе, если групп несколько
Рассмотрим работу findall на примере вывода команды sh mac address-table:
In [2]: mac_address_table = open('CAM_table.txt').read() In [3]: print(mac_address_table) sw1#sh mac address-table Mac Address Table ------------------------------------------- Vlan Mac Address Type Ports ---- ----------- -------- ----- 100 a1b2.ac10.7000 DYNAMIC Gi0/1 200 a0d4.cb20.7000 DYNAMIC Gi0/2 300 acb4.cd30.7000 DYNAMIC Gi0/3 100 a2bb.ec40. 7000 DYNAMIC Gi0/4 500 aa4b.c550.7000 DYNAMIC Gi0/5 200 a1bb.1c60.7000 DYNAMIC Gi0/6 300 aa0b.cc70.7000 DYNAMIC Gi0/7
Первый пример - регулярное выражение без групп. В этом случае findall возвращает список строк, которые совпали с регулярным выражением.
Например, с помощью findall можно получить список строк с соответствиями vlan - mac - interface и избавиться от заголовка в выводе команды:
In [4]: re.findall(r'\d+ +\S+ +\w+ +\S+', mac_address_table) Out[4]: ['100 a1b2.ac10.7000 DYNAMIC Gi0/1', '200 a0d4.cb20.7000 DYNAMIC Gi0/2', '300 acb4.cd30.7000 DYNAMIC Gi0/3', '100 a2bb.ec40.7000 DYNAMIC Gi0/4', '500 aa4b.c550.7000 DYNAMIC Gi0/5', '200 a1bb.1c60.7000 DYNAMIC Gi0/6', '300 aa0b.cc70.7000 DYNAMIC Gi0/7']
Обратите внимание, что findall возвращает список строк, а не объект Match.
Как только в регулярном выражении появляется группа, findall ведет себя по-другому. Если в выражении используется одна группа, findall возвращает список строк, которые совпали с выражением в группе:
In [5]: re.findall(r'\d+ +(\S+) +\w+ +\S+', mac_address_table) Out[5]: ['a1b2.ac10.7000', 'a0d4.cb20.7000', 'acb4.cd30.7000', 'a2bb.ec40.7000', 'aa4b.c550.7000', 'a1bb.1c60.7000', 'aa0b.cc70.7000']
При этом findall ищет совпадение всей строки, но возвращает результат, похожий на метод groups() в объекте Match.
Если же групп несколько, findall вернет список кортежей:
In [6]: re.findall(r'(\d+) +(\S+) +\w+ +(\S+)', mac_address_table) Out[6]: [('100', 'a1b2.ac10.7000', 'Gi0/1'), ('200', 'a0d4.cb20.7000', 'Gi0/2'), ('300', 'acb4.cd30.7000', 'Gi0/3'), ('100', 'a2bb.ec40.7000', 'Gi0/4'), ('500', 'aa4b.c550.7000', 'Gi0/5'), ('200', 'a1bb.1c60.7000', 'Gi0/6'), ('300', 'aa0b.cc70.7000', 'Gi0/7')]
Если такие особенности работы функции findall мешают получить необходимый результат, то лучше использовать функцию finditer, но иногда такое поведение подходит и удобно использовать.
Пример использования findall в разборе лог-файла (файл parse_log_findall.py):
import re regex = (r'Host \S+ ' r'in vlan (\d+) ' r'is flapping between port ' r'(\S+) and port (\S+)') ports = set() with open('log.txt') as f: result = re.findall(regex, f.read()) for vlan, port1, port2 in result: ports.add(port1) ports.add(port2) print('Петля между портами {} в VLAN {}'.format(', '.join(ports), vlan))
Результат:
$ python parse_log_findall.py Петля между портами Gi0/19, Gi0/16, Gi0/24 в VLAN 10
re.findall в Python 3 - CodeRoad
Я хотел использовать функцию re.findall(), которая ищет на веб-странице определенный шаблон:
from urllib.request import Request, urlopen
import re
url = Request('http://www.cmegroup.com/trading/products/#sortField=oi&sortAsc=false&venues=3&page=1&cleared=1&group=1', headers={'User-Agent': 'Mozilla/20. 0.1'})
webpage = urlopen(url).read()
findrows = re.compile('<td>(.*)</td>')
row_array = re.findall(findrows, webpage) #ERROR HERE
Я получаю ошибку:
TypeError: can't use a string pattern on a bytes-like object
python
regex
web Поделиться Источник Josh 18 мая 2013 в 20:28
3 ответа
- Почему python re.findall не возвращает все найденные подстроки в моем примере?
Возможный Дубликат : Python regex найти все перекрывающиеся совпадения? Я не понимаю, почему python re.findall не возвращает все найденные подстроки в моем примере ниже. Есть идеи? >>> import re import re >>> t='1 2 3' t='1 2 3' >>> m=re.findall('\d\s\d',t)...
- Python re.findall() и приоритет
Как я могу использовать функцию re.findall() для получения списка экземпляров соответствия, когда я использую вложенные скобки в шаблоне regex для учета приоритета? Пример: import re string = 'blah blah 12234 (12) (23) (34)' print re. findall(r'\((\d)+)\)', string) Это отпечатки пальцев: [('12',...
6
urllib.request.urlopen
возвращает объект bytes
, а не строку (Unicode). Вы должны расшифровать его, прежде чем пытаться сопоставить что-либо. Например, если вы знаете, что ваша страница находится в UTF-8:
webpage = urlopen(url).read().decode('utf8')
Лучшие библиотеки HTTP автоматически сделают это за вас, но определение правильной кодировки не всегда тривиально или даже возможно, поэтому стандартная библиотека Python этого не делает.
Другой вариант-использовать вместо этого bytes
regex:
findrows = re.compile(b'<td>(.*)</td>')
Это полезно, если вы также не знаете кодировки и не возражаете работать с объектами bytes
по всему вашему коду.
Поделиться Cairnarvon 18 мая 2013 в 20:39
2
Сначала вам нужно декодировать объект bytes:
data = urlopen(url). read()
webpage = data.decode('utf-8') #converts `bytes` to `str`
findrows.findall(webpage)
Поделиться Ashwini Chaudhary 18 мая 2013 в 20:36
0
Вы можете скомпилировать регулярное выражение байт :
re.compile(b"yourpatternhere")
Поделиться Max 18 мая 2013 в 21:02
- Python re.findall С * и **
используя re.findall, можно ли перечислить два последующих вхождения * в один и тот же индекс списка? допустим, у меня есть str = 2**3 + 2*3 я бы хотел, чтобы список выглядел следующим образом lis = re.findall('[\+\-*/()]', str) lis = [2, **, 3, +, 2, *, 3] есть ли какие-то regex, как *|** ?
- re.findall ведет себя странно
Исходная строка: # Python 3.4.3 s = r'abc123d, hello 3. 1415926, this is my book' и вот мой образец: pattern = r'-?[0-9]+(\\.[0-9]*)?|-?\\.[0-9]+' однако re.search может дать мне правильный результат: m = re.search(pattern, s) print(m) # output: <_sre.SRE_Match object; span=(3, 6),...
Похожие вопросы:
Использование любого в re.findall - Python
Я написал сценарий в python, чтобы сказать, какие числа в new были в первых 10 числах в new. Я знаю, что это выглядит сложнее, чем есть, и это связано с тем, что я пытаюсь сделать со сценарием...
Python регулярные выражения-re.search() против re.findall()
Для школы я должен написать сценарий Python RE, который извлекает IP адресов. Регулярное выражение, которое я использую, похоже, работает с re.search() , но не с re.findall() . exp =...
Python re.search() и re.findall()
Я пытаюсь решить эту проблему с помощью HackerRank . Это проблема машинного обучения. Сначала я попытался прочитать все слова из файла корпуса для построения униграмм частот. В соответствии с этим...
Почему python re.findall не возвращает все найденные подстроки в моем примере?
Возможный Дубликат : Python regex найти все перекрывающиеся совпадения? Я не понимаю, почему python re.findall не возвращает все найденные подстроки в моем примере ниже. Есть идеи? >>>...
Python re.findall() и приоритет
Как я могу использовать функцию re.findall() для получения списка экземпляров соответствия, когда я использую вложенные скобки в шаблоне regex для учета приоритета? Пример: import re string = 'blah...
Python re.findall С * и **
используя re.findall, можно ли перечислить два последующих вхождения * в один и тот же индекс списка? допустим, у меня есть str = 2**3 + 2*3 я бы хотел, чтобы список выглядел следующим образом lis =...
re.findall ведет себя странно
Исходная строка: # Python 3. 4.3 s = r'abc123d, hello 3.1415926, this is my book' и вот мой образец: pattern = r'-?[0-9]+(\\.[0-9]*)?|-?\\.[0-9]+' однако re.search может дать мне правильный...
Python 3 re.findall закрытие файла?
1) я открываю файл 2) run re.findall() возвращает список, как и ожидалось 3) Затем я снова запускаю re.findall() в поисках чего-то другого, но он возвращает пустой список. Но если я снова открою...
Python regex с re.findall
Я работаю с Python 2.7. Это мой первый вопрос. Вот мой код: import re string = 0581111105822222749533333 result = re.findall(r'058',string) # ['058', '058'] Я хочу добавить 5 цифр после 058 и...
re.findall от python до Java совпадений, паттернов
Я хочу преобразовать свой re.findall(regex) в java. Я знаю, как использовать совпадение и шаблон, но мне придется компилировать его много раз, когда у меня есть несколько шаблонов regex, чтобы...
Модуль Python Re на примерах + задания и шаблоны ~ PythonRu
Регулярные выражения, также называемые regex, синтаксис или, скорее, язык для поиска, извлечения и работы с определенными текстовыми шаблонами большего текста. Он широко используется в проектах, которые включают проверку текста, NLP (Обработка естественного языка) и интеллектуальную обработку текста.
Введение в регулярные выражения
Регулярные выражения, также называемые regex, используются практически во всех языках программирования. В python они реализованы в стандартном модуле re
.
Он широко используется в естественной обработке языка, веб-приложениях, требующих проверки ввода текста (например, адреса электронной почты) и почти во всех проектах в области анализа данных, которые включают в себя интеллектуальную обработку текста.
Эта статья разделена на 2 части.
Прежде чем перейти к синтаксису регулярных выражений, для начала вам лучше понять, как работает модуль re
.
Итак, сначала вы познакомитесь с 5 основными функциями модуля re
, а затем посмотрите, как создавать регулярные выражения в python.
Узнаете, как построить практически любой текстовый шаблон, который вам, скорее всего, понадобится при работе над проектами, связанными с поиском текста.
Что такое шаблон регулярного выражения и как его скомпилировать?
Шаблон регулярного выражения представляет собой специальный язык, используемый для представления общего текста, цифр или символов, извлечения текстов, соответствующих этому шаблону.
Основным примером является \s+
.
Здесь \ s
соответствует любому символу пробела. Добавив в конце оператор +
, шаблон будет иметь не менее 1 или более пробелов. Этот шаблон будет соответствовать даже символам tab \t
.
В конце этой статьи вы найдете больший список шаблонов регулярных выражений. Но прежде чем дойти до этого, давайте посмотрим, как компилировать и работать с регулярными выражениями.
>>> import re
>>> regex = re.compile('\s+')
Вышеупомянутый код импортирует модуль re
и компилирует шаблон регулярного выражения, который соответствует хотя бы одному или нескольким символам пробела.
Как разбить строку, разделенную регулярным выражением?
Рассмотрим следующий фрагмент текста.
>>> text = """100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский"""
У меня есть три курса в формате “[Номер курса] [Код курса] [Название курса]”. Интервал между словами разный.
Передо мной стоит задача разбить эти три предмета курса на отдельные единицы чисел и слов. Как это сделать?
Их можно разбить двумя способами:
- Используя метод
re.split
. - Вызвав метод
split
для объектаregex
.
>>> re.split('\s+', text)
>>> regex.split(text)
['100', 'ИНФ', 'Информатика', '213', 'МАТ', 'Математика', '156', 'АНГ', 'Английский']
Оба эти метода работают. Но какой же следует использовать на практике?
Если вы намерены использовать определенный шаблон несколько раз, вам лучше скомпилировать регулярное выражение, а не использовать re. split
множество раз.
Поиск совпадений с использованием findall, search и match
Предположим, вы хотите извлечь все номера курсов, то есть 100, 213 и 156 из приведенного выше текста. Как это сделать?
Что делает re.findall()?
>>> print(text)
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
>>> regex_num = re.compile('\d+')
>>> regex_num.findall(text)
['100', '213', '156']
В приведенном выше коде специальный символ \ d
является регулярным выражением, которое соответствует любой цифре. В этой статье вы узнаете больше о таких шаблонах.
Добавление к нему символа +
означает наличие по крайней мере 1 числа.
Подобно +
, есть символ *
, для которого требуется 0 или более чисел. Это делает наличие цифры не обязательным, чтобы получилось совпадение. Подробнее об этом позже.
В итоге, метод findall
извлекает все вхождения 1 или более номеров из текста и возвращает их в список.
re.search() против re.match()
Как понятно из названия, regex.search()
ищет шаблоны в заданном тексте.
Но, в отличие от findall
, который возвращает согласованные части текста в виде списка, regex.search()
возвращает конкретный объект соответствия. Он содержит первый и последний индекс первого соответствия шаблону.
Аналогично, regex.match()
также возвращает объект соответствия. Но разница в том, что он требует, чтобы шаблон находился в начале самого текста.
>>>
>>> text2 = """ИНФ Информатика
213 МАТ Математика 156"""
>>>
>>> regex_num = re.compile('\d+')
>>> s = regex_num.search(text2)
>>> print('Первый индекс: ', s.start())
>>> print('Последний индекс: ', s.end())
>>> print(text2[s.start():s.end()])
Первый индекс: 17
Последний индекс: 20
213
В качестве альтернативы вы можете получить тот же результат, используя метод group()
для объекта соответствия.
>>> print(s.group())
205
>>> m = regex_num.match(text2)
>>> print(m)
None
Как заменить один текст на другой, используя регулярные выражения?
Для изменения текста, используйте regex.sub()
.
Рассмотрим следующую измененную версию текста курсов. Здесь добавлена табуляция после каждого кода курса.
>>> text = """100 ИНФ \t Информатика
213 МАТ \t Математика
156 АНГ \t Английский"""
>>> print(text)
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
Из вышеприведенного текста я хочу удалить все лишние пробелы и записать все слова в одну строку.
Для этого нужно просто использовать regex.sub
для замены шаблона \s+
на один пробел .
>>> regex = re.compile('\s+')
>>> print(regex.sub(' ', text))
или
>>> print(re. sub('\s+', ' ', text))
101 COM Computers 205 MAT Mathematics 189 ENG English
Предположим, вы хотите избавиться от лишних пробелов и выводить записи курса с новой строки. Чтобы это сделать, используйте регулярное выражение, которое пропускает символ новой строки, но учитывает все другие пробелы.
Это можно сделать, используя отрицательное соответствие (?!\n)
. Шаблон проверяет наличие символа новой строки, в python это \n
, и пропускает его.
>>> regex = re.compile('((?!\n)\s+)')
>>> print(regex.sub(' ', text))
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
Группы регулярных выражений
Группы регулярных выражений — функция, позволяющая извлекать нужные объекты соответствия как отдельные элементы.
Предположим, что я хочу извлечь номер курса, код и имя как отдельные элементы. Не имея групп мне придется написать что-то вроде этого.
>>> text = """100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский"""
>>> re.findall('[0-9]+', text)
>>> re.findall('[А-ЯЁ]{3}', text)
>>> re.findall('[а-яА-ЯёЁ]{4,}', text)
['100', '213', '156']
['ИНФ', 'МАТ', 'АНГ']
['Информатика', 'Математика', 'Английский']
Давайте посмотрим, что получилось.
Я скомпилировал 3 отдельных регулярных выражения по одному для соответствия номерам курса, коду и названию.
Для номера курса, шаблон [0-9]+
указывает на соответствие всем числам от 0 до 9. Добавление символа +
в конце заставляет найти по крайней мере 1 соответствие цифрам 0-9. Если вы уверены, что номер курса, будет иметь ровно 3 цифры, шаблон мог бы быть [0-9] {3}
.
Для кода курса, как вы могли догадаться, [А-ЯЁ]{3}
будет совпадать с 3 большими буквами алфавита А-Я подряд (буква “ё” не включена в общий диапазон букв).
Для названий курса, [а-яА-ЯёЁ]{4,}
будем искать а-я верхнего и нижнего регистра, предполагая, что имена всех курсов будут иметь как минимум 4 символа.
Можете ли вы догадаться, каков будет шаблон, если максимальный предел символов в названии курса, скажем, 20?
Теперь мне нужно написать 3 отдельные строки, чтобы разделить предметы. Но есть лучший способ. Группы регулярных выражений.
Поскольку все записи имеют один и тот же шаблон, вы можете создать единый шаблон для всех записей курса и внести данные, которые хотите извлечь из пары скобок ().
>>> course_pattern = '([0-9]+)\s*([А-ЯЁ]{3})\s*([а-яА-ЯёЁ]{4,})'
>>> re.findall(course_pattern, text)
[('100', 'ИНФ', 'Информатика'), ('213', 'МАТ', 'Математика'), ('156', 'АНГ', 'Английский')]
Обратите внимание на шаблон номера курса: [0-9]+
, код: [А-ЯЁ]{3}
и название: [а-яА-ЯёЁ]{4,}
они все помещены в круглую скобку (), для формирования группы.
Что такое “жадное” соответствие в регулярных выражениях?
По умолчанию, регулярные выражения должны быть жадными. Это означает, что они пытаются извлечь как можно больше, пока соответствуют шаблону, даже если требуется меньше.
Давайте рассмотрим пример фрагмента HTML, где нам необходимо получить тэг HTML.
>>> text = "<body>Пример жадного соответствия регулярных выражений</body>"
>>> re.findall('<.*>', text)
['<body>Пример жадного соответствия регулярных выражений</body>']
Вместо совпадения до первого появления ‘>’, которое, должно было произойти в конце первого тэга тела, он извлек всю строку. Это по умолчанию “жадное” соответствие, присущее регулярным выражениям.
С другой стороны, ленивое соответствие “берет как можно меньше”. Это можно задать добавлением ?
в конец шаблона.
>>> re.findall('<.*?>', text)
['<body>', '</body>']
Если вы хотите получить только первое совпадение, используйте вместо этого метод поиска search
.
re.search('<.*?>', text).group()
'<body>'
Наиболее распространенный синтаксис и шаблоны регулярных выражений
Теперь, когда вы знаете как пользоваться модулем re, давайте рассмотрим некоторые обычно используемые шаблоны подстановок.
Основной синтаксис
. | Один символ кроме новой строки |
\. | Просто точка . , обратный слеш \ убирает магию всех специальных символов. |
\d | Одна цифра |
\D | Один символ кроме цифры |
\w | Один буквенный символ, включая цифры |
\W | Один символ кроме буквы и цифры |
\s | Один пробельный (включая таб и перенос строки) |
\S | Один не пробельный символ |
\b | Границы слова |
\n | Новая строка |
\t | Табуляция |
Модификаторы
$ | Конец строки | |
^ | Начало строки | |
ab|cd | Соответствует ab или de. ab-d] | Любой символ, кроме: a, b, c, d |
() | Извлечение элементов в скобках | |
(a(bc)) | Извлечение элементов в скобках второго уровня |
Повторы
[ab]{2} | 2 непрерывных появления a или b |
[ab]{2,5} | от 2 до 5 непрерывных появления a или b |
[ab]{2,} | 2 и больше непрерывных появления a или b |
+ | одно или больше |
* | 0 или больше |
? | 0 или 1 |
Примеры регулярных выражений
Любой символ кроме новой строки
>>> text = 'python.org'
>>> print(re.findall('.', text))
['p', 'y', 't', 'h', 'o', 'n', '.', 'o', 'r', 'g']
>>> print(re.findall('...', text))
['pyt', 'hon', '.or']
Точки в строке
>>>text = 'python. \.]', text))
['p', 'y', 't', 'h', 'o', 'n', 'o', 'r', 'g']
Любая цифра
>>> text = '01, Янв 2018'
>>> print(re.findall('\d+', text))
['01', '2018']
Все, кроме цифры
>>> text = '01, Янв 2018'
>>> print(re.findall('\D+', text))
[', Янв ']
Любая буква или цифра
>>> text = '01, Янв 2018'
>>> print(re.findall('\w+', text))
['01', 'Янв', '2018']
Все, кроме букв и цифр
>>> text = '01, Янв 2018'
>>> print(re.findall('\W+', text))
[', ', ' ']
Только буквы
>>> text = '01, Янв 2018'
>>> print(re.findall('[а-яА-ЯёЁ]+', text))
['Янв']
Соответствие заданное количество раз
>>> text = '01, Янв 2018'
>>> print(re. findall('\d{4}', text))
['2018']
>>> print(re.findall('\d{2,4}', text))
['01', '2018']
1 и более вхождений
>>> print(re.findall(r'Co+l', 'So Cooool'))
['Cooool']
Любое количество вхождений (0 или более раз)
>>> print(re.findall(r'Pi*lani', 'Pilani'))
['Pilani']
0 или 1 вхождение
>>> print(re.findall(r'colou?r', 'color'))
['color']
Граница слова
Границы слов \b
обычно используются для обнаружения и сопоставления началу или концу слова. То есть, одна сторона является символом слова, а другая сторона является пробелом и наоборот.
Например, регулярное выражение \btoy
совпадает с ‘toy’ в ‘toy cat’, но не в ‘tolstoy’. Для того, чтобы ‘toy’ соответствовало ‘tolstoy’, используйте toy\b
.
Можете ли вы придумать регулярное выражение, которое будет соответствовать только первой ‘toy’в ‘play toy broke toys’? (подсказка: \ b
с обеих сторон)
Аналогично, \ B
будет соответствовать любому non-boundary( без границ).
Например, \ Btoy \ B
будет соответствовать ‘toy’, окруженной словами с обеих сторон, как в ‘antoynet’.
>>> re.findall(r'\btoy\b', 'play toy broke toys')
['toy']
Практические упражнения
Давайте немного попрактикуемся. Пришло время открыть вашу консоль. (Варианты ответов здесь)
1. Извлеките никнейм пользователя, имя домена и суффикс из данных email адресов.
emails = """[email protected]
[email protected]
[email protected]"""
[('zuck26', 'facebook', 'com'), ('page33', 'google', 'com'), ('jeff42', 'amazon', 'com')]
2. Извлеките все слова, начинающиеся с ‘b’ или ‘B’ из данного текста.
text = """Betty bought a bit of butter, But the butter was so bitter, So she bought some better butter, To make the bitter butter better."""
['Betty', 'bought', 'bit', 'butter', 'But', 'butter', 'bitter', 'bought', 'better', 'butter', 'bitter', 'butter', 'better']
3. Уберите все символы пунктуации из предложения
sentence = """A, very very; irregular_sentence"""
A very very irregular sentence
4. Очистите следующий твит, чтобы он содержал только одно сообщение пользователя. То есть, удалите все URL, хэштеги, упоминания, пунктуацию, RT и CC.
tweet = '''Good advice! RT @TheNextWeb: What I would do differently if I was learning to code today https://t.co/lbwej0pxOd cc: @garybernhardt #rstats'''
'Good advice What I would do differently if I was learning to code today'
- Извлеките все текстовые фрагменты между тегами с HTML страницы: https://raw. githubusercontent.com/selva86/datasets/master/sample.html
Код для извлечения HTML страницы:
import requests
r = requests.get("https://raw.githubusercontent.com/selva86/datasets/master/sample.html")
r.text
['Your Title Here', 'Link Name', 'This is a Header', 'This is a Medium Header', 'This is a new paragraph! ', 'This is a another paragraph!', 'This is a new sentence without a paragraph break, in bold italics.']
Ответы
>>> pattern = r'(\w+)@([A-Z0-9]+)\.([A-Z]{2,4})'
>>> re.findall(pattern, emails, flags=re.IGNORECASE)
[('zuck26', 'facebook', 'com'), ('page33', 'google', 'com'), ('jeff42', 'amazon', 'com')]
Есть больше шаблонов для извлечения домена и суфикса. Это лишь один из них.
>>> import re
>>> re.findall(r'\bB\w+', text, flags=re.IGNORECASE)
['Betty', 'bought', 'bit', 'butter', 'But', 'butter', 'bitter', 'bought', 'better', 'butter', 'bitter', 'butter', 'better']
\b
находится слева от ‘B’, значит слово должно начинаться на ‘B’. _`{|}~"""), '', tweet)
tweet = re.sub('\s+', ' ', tweet)
return tweet
>>> print(clean_tweet(tweet))
'Good advice What I would do differently if I was learning to code today'
>>> re.findall('<.*?>(.*)</.*?>', r.text)
['Your Title Here', 'Link Name', 'This is a Header', 'This is a Medium Header', 'This is a new paragraph! ', 'This is a another paragraph!', 'This is a new sentence without a paragraph break, in bold italics.']
Надеемся, информация была вам полезна. Стояла цель — познакомить вас с примерами регулярных выражений легким и доступным для запоминания способом.
Python Regex Search
Когда я впервые узнал о регулярных выражениях, я не оценил их силу. Но есть причина, по которой регулярные выражения пережили семь десятилетий технологического сбоя: программисты, понимающие регулярные выражения, имеют огромное преимущество при работе с текстовыми данными. Они могут написать в одной строке кода выражение, что занимает десятки других!
Как re.search() работает в Python?
Метод re.search(pattern, string) сопоставляет первое вхождение шаблона в строке и возвращает объект соответствия.
Спецификация :
re. search(pattern, string, flags=0)
Метод re.search() имеет до трех аргументов.
- pattern: шаблон регулярного выражения, который вы хотите сопоставить.
- string: строка, которую вы хотите найти для шаблона.
- flags(необязательный аргумент): более продвинутый модификатор, который позволяет вам настроить поведение функции.
Мы рассмотрим их более подробно позже.
Метод re.search() возвращает объект соответствия. Вы можете спросить (и это правильно):
Что такое объект соответствия?
Если регулярное выражение совпадает с частью вашей строки, с ней приходит много полезной информации: какова точная позиция соответствия? Какие группы регулярных выражений были сопоставлены и где?
Объект соответствия является простой оболочкой для этой информации. Некоторые методы регулярных выражений re-package в Python, такие как search()
, автоматически создают объект соответствия при первом сопоставлении с образцом.
На этом этапе вам не нужно детально исследовать объект соответствия. Просто знайте, что мы можем получить доступ к начальной и конечной позициям совпадения в строке, вызвав методы m.start()
и m.end()
для объекта соответствия m
:
m = re.search('h...o', 'hello world')
m.start()
# 0
m.end()
# 5
'hello world'[m.start():m.end()]
# 'hello'
В первой строке вы создаете объект m с помощью метода re.search(). Шаблон ‘h… o
‘ совпадает в строке ‘hello world’ в начальной позиции 0. Вы используете начальную и конечную позиции для доступа к подстроке, которая соответствует шаблону.
Руководствуясь примером для re.search()
Сначала вы импортируете модуль re
и создаете текстовую строку для поиска шаблонов регулярных выражений:
import re
text = '''
Ha! let me see her: out, alas! he's cold:
Her blood is settled, and her joints are stiff;
Life and these lips have long been separated:
Death lies on her like an untimely frost
Upon the sweetest flower of all the field.
'''
Допустим, вы хотите найти в тексте строку «her»:
Первый аргумент — образец, который нужно найти. В нашем случае это строка «her». Второй аргумент — это текст для анализа. Вы сохранили многострочную строку в переменной — так что вы берете ее в качестве второго аргумента.
Посмотрите на вывод: это объект соответствия! Объект match дает диапазон совпадения, то есть индексы начала и конца совпадения. Мы также можем напрямую получить доступ к этим границам, используя методы start()
и stop()
объекта match:
m = re.search('her', text)
m.start()
#20
m.end()
# 23
Проблема в том, что метод search()
извлекает только первое вхождение шаблона в строке. Если вы хотите найти все совпадения в строке, вы можете использовать метод findall() библиотеки re.
В чем разница между re.search() и re.findall()?
Существует два различия между методами re.search(pattern, string)
и re.findall(pattern, string)
:
re.search(pattern, string)
возвращает объект соответствия, аre.findall(pattern, string)
возвращает список совпадающих строк.re.search(pattern, string)
возвращает только первое совпадение в строке, аre.findall(pattern, string)
возвращает все совпадения в строке.
Оба можно увидеть в следующем примере:
text = 'Python is superior to Python'
re.search('Py...n', text)
#
re.findall('Py...n', text)
# ['Python', 'Python']
Строка «Python is superior to Python» содержит два вхождения «Python». Метод search()
возвращает только объект соответствия первого вхождения. Метод findall()
возвращает список всех вхождений.
В чем разница между re.search() и re.match()?
Методы re.search(pattern, string)
и re.match(pattern, string)
оба возвращают объект соответствия первого соответствия. Однако re.match()
пытается найти совпадение в начале строки, а re.search()
— в любом месте строки.
Вы можете увидеть эту разницу в следующем коде:
text = 'Slim Shady is my name'
re.search('Shady', text)
#
re.match('Shady', text)
# empty
Метод re.search()
извлекает совпадение подстроки ‘Shady’ как объект сопоставления. Но если вы используете метод re.match()
, совпадения и возвращаемого значения не будет, потому что подстрока ‘Shady’ не встречается в начале строки ‘Slim Shady is my name’.
Как использовать необязательный аргумент flag?
Как вы видели в спецификации, метод search()
поставляется с необязательным третьим аргументом ‘flag’:
re.search(pattern, string, flags=0)
Какова цель аргумента flag?
Флаги позволяют вам управлять механизмом регулярных выражений. Поскольку регулярные выражения настолько мощны, они являются полезным способом включения и выключения определенных функций (например, игнорировать ли заглавные буквы при сопоставлении с регулярным выражением).
re.ASCII | Если вы не используете этот флаг, специальные символы регулярного выражения Python \w, \W, \b, \B, \d, \D, \s и \S будут соответствовать символам Юникода. Если вы используете этот флаг, эти специальные символы будут соответствовать только символам ASCII — как следует из названия. |
re.A | То же, что и re.ASCII |
re.DEBUG | Если вы используете этот флаг, Python выведет некоторую полезную информацию в оболочку, которая поможет вам отладить ваше регулярное выражение. |
re.IGNORECASE | Если вы используете этот флаг, механизм регулярных выражений выполнит сопоставление без учета регистра. Поэтому, если вы ищете [AZ], оно также будет соответствовать [az]. |
re.I | То же, что и re.IGNORECASE |
re.LOCALE | Не используйте этот флаг — никогда. Это устарело — идея заключалась в том, чтобы выполнять сопоставление без учета регистра в зависимости от вашей текущей локали. Но это не надежно. |
re.L | То же, что и re.LOCALE |
re.M | То же, что и re.MULTILINE |
re.DOTALL | Без использования этого флага точка regex ‘.’ соответствует всем символам, кроме символа новой строки ‘\n’. Включите этот флаг, чтобы он действительно соответствовал всем символам, включая символ новой строки. |
re.S | То же, что и re.DOTALL |
re.VERBOSE | Чтобы улучшить читаемость сложных регулярных выражений, вы можете разрешить комментарии и (многострочное) форматирование самого регулярного выражения. Это возможно с этим флагом: все пробельные символы и строки, начинающиеся с символа «#», игнорируются в регулярном выражении. |
re.X | То же, что и re.VERBOSE |
text = 'Python is great!'
re.search('PYTHON', text, flags=re.IGNORECASE)
#
Хотя в вашем регулярном выражении ‘PYTHON’ прописные буквы, мы игнорируем заглавные буквы, используя флаг re.IGNORECASE.
основы NLP и Data Science
Регулярные выражения (regular expressions) являются важнейшим инструментом для многих задач NLP в Python. Сегодня мы расскажем об основных функциях Python-модуля re. Читайте в этой статье: как с помощью регулярных выражений найти нужные символы, как посчитать количество вхождений, а также как заменить одну подстроку на другую в Python
Зачем нужны регулярные выражения
Регулярные выражения — последовательность символов, которая определяет шаблон поиска. Например, для задач NLP это может быть поиск именованных сущностей (для такой задачи может подойти Python-библиотека Yargy). Представим себе выражение:
Python is cool
Требуется извлечь из него слово «cool». Казалось бы, сделать это очень просто, достаточно передать это слово в Python-функцию с регулярным выражением. Но поскольку это набор символов, то выражения, которые содержат этот набор также сработают:
Python is coolest I have a watercooler Python is supercool
Регулярные выражения в Python
Для работы с регулярными выражениями в Python используется модуль re
(сокращено от regular expression). В нем содержится 4 основные функции: search
, match
, findall
, finditer
, а также sub
Причём у первых 4-х одинаковая сигнатура — принимают на вход шаблон и выражение. Обращаясь к предыдущему примеру, шаблоном является «cool». Функция sub
дополнительно принимает на вход строку для замены.
Ищем первый попавшийся шаблон с search
Функция search
найдёт в выражении первый попавшийся шаблон. Нам нужно найти шаблон, который состоит из последовательности символов c, o, o, l. Поэтому передаём в функцию этот шаблон и выражение. Такое регулярное выражение в Python выглядит следующим образом:
>>> import re >>> expr = 'Python is cool' >>> pattern = 'cool' >>> re.search(pattern, expr) <re.Match object; span=(10, 14), match='cool'>
Мы получили объект Match, а span
показывает индексы шаблона в выражении. Поэтому его так же можно извлечь в Python:
>>> expr[10:14] 'cool'
Заметим, что функция search
находит только первый попавшийся шаблон, дальше она уже не смотрит:
>>> expr = 'Python is cool, very cool' >>> re.search(pattern, expr) <re.Match object; span=(10, 14), match='cool'>
Также не забываем, что шаблон — это последовательность символов, а не само слово. Например, ниже показано, как в Python находится последовательность «cool» в составном слове.
>>> expr = 'I have a watercooler' >>> re.search('cool', expr) <re.Match object; span=(14, 18), match='cool'>
Ищем все вхождения с findall и finditer
В отличие от функции search
, две других findall
и finditer
вернут все найденные вхождения. Отличаются findall
и finditer
друг от друга тем, что первый возвращает список (list), а второй итератор (iterator), о котором говорили тут. Возвращаясь к предыдущему примеру, регулярное выражение для нахождения всех совпадений в Python будет выглядеть так:
>>> expr = 'Python is cool, very cool' >>> re.findall('cool', expr) ['cool', 'cool'] >>> re.finditer('cool', expr) <callable_iterator object at 0x7fe095db00d0>
С помощью функции findall
можно посчитать количество шаблонов во всей строке:
>>> len(re.findall('cool', expr)) 2
Проверяем начало строки с match
Функция match
проверит начало строки на содержание шаблона. Пример выше не начинается с cool, поэтому эта функция вернёт None
. С другой стороны, если выражение начинается с шаблона, то функция match
вернёт объект Match. Рассмотрите следующие регулярные выражения в Python:
>>> expr = 'Python is cool' >>> re.match('Python', expr) <re.Match object; span=(0, 6), match='Python'> >>> re.match('cool', expr) is None True
Исключаем шаблон из строки с sub
Ещё одной полезной функцией Python-модуля re является sub
. Она необходима, когда один шаблон нужно заменить на другой и пригодится для подготовки текстов перед применением NLP-методов в Python, например, для избавления от всех цифр, знаков препинания и символов. К сигнатуре этой функции добавляется аргумент repl
— на какую строку заменяем. Ниже регулярные выражения в Python это демонстрируют. Обратите внимание, что sub
возвращает строку, поэтому их стоит переприсвоить.
>>> expr = 'Python is cool, very cool' >>> pattern = 'cool' >>> repl = 'slow' >>> re.sub(pattern, repl, expr) 'Python is slow, very slow'
Также отметим, что функция заменяет все вхождения. Если требуется ограничить это число, то оно указывается в аргументе count
.
>>> re.sub(pattern, repl, expr, count=1) 'Python is slow, very cool'
Ещё больше подробностей о работе регулярных выражения в Python на реальных примерах Data Science задач, вы узнаете на нашем специализированном курсе «PNLP: NLP – обработка естественного языка с Python» в лицензированном учебном центре обучения и повышения квалификации Data Scientist’ов и IT-специалистов в Москве.
Источники
- https://docs.python.org/3/howto/regex.html
Руководство по использованию регулярных выражений Python
Одна из главных задач при работе с текстовыми данными — это создание множества текстовых функций.
Некоторые функции ищут конкретные паттерны в тексте, например, адреса электронной почты или номера телефонов.
Создание этого функционала может казаться довольно тривиальным, но значительно проще использовать модули регулярных выражений.
Например, нужно посчитать количество знаков препинания в конкретном куске текста. Используем отрывок из Диккенса (оригинал).
Как бы вы это сделали?
Достаточно простой путь, к примеру, такой:
target = [';','.',',','–']
string = "It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way – in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only."
num_puncts = 0
for punct in target:
if punct in string:
num_puncts+=string.count(punct)print(num_puncts)
------------------------------------------------------------------
19
Это нормально, но в нашем распоряжении есть модуль re, с ним получается всего 2 строчки кода:
import re
pattern = r"[;.,–]"
print(len(re.findall(pattern,string)))
------------------------------------------------------------------
19
Эта статья посвящена наиболее часто используемым паттернам регулярных выражений, а также некоторым функциям регулярных выражений.
Что такое
регулярные выражения
?Проще говоря, регулярное выражение используется для поиска паттернов в указанной строке.
Паттерном может быть все что угодно.
Можно создавать паттерны соответствия электронной почте или мобильному номеру. Можно создать паттерны, которые ищут слова в строке, начинающиеся на “a” и заканчивающиеся на “z”.
В примере выше:
import re
pattern = r'[,;.,–]'
print(len(re.findall(pattern,string)))
Паттерн, который нужно найти — r’[,;.,–]’
. Он выделяет любой из четырех символов. Я нашел regex101, прекрасный инструмент для тестирования паттернов. Вот как выглядит данный паттерн, примененный к строке.
Как видим, мы можем найти любое из значений ,;.,–
в указанной строке.
Я использую этот инструмент всегда, когда мне нужно протестировать регулярное выражение. Так значительно быстрее, чем запускать python снова и снова, и гораздо проще при отладке.
Теперь мы знаем, что можем найти паттерны в целевой строке, но как создавать эти паттерны?
Создание паттернов
Первое, что нужно освоить в работе с регулярными выражениями, — это создание паттернов.
Рассмотрим некоторые наиболее часто используемые паттерны.
Простейший паттерн — это просто строка.
pattern = r'times'
string = "It was the best of times, it was the worst of times."
print(len(re.findall(pattern,string)))
Но это не очень полезно. Для создания сложных паттернов регулярные выражения содержат специальные символы/операторы. Давайте рассмотрим эти операторы по очереди.
1. Оператор “[ ]"
Этот оператор использовался в первом примере. Мы ищем любой из символов в квадратных скобках.
[abc]
— найдет a, b, и c.
[a-z]
— найдет все значения от a до z.
[a-z0–9A-Z]
— найдет значения от a до z, от A до Z и от 0 до 9.
В Python этот паттерн использовать легко:
pattern = r'[a-zA-Z]'
string = "It was the best of times, it was the worst of times."
print(len(re.findall(pattern,string)))
В регулярных выражениях есть и другие функции, кроме .findall
, но мы вернемся к ним чуть позже.
2. Оператор точки
Оператор точки (.) используется для поиска соответствия любому единичному символу, кроме символа новой строки.
Самое классное в этом операторе то, что его можно использовать в сочетании с другими.
Например, нужно найти в строке подстроки длиной в 6 знаков, начинающиеся с маленькой “d” и заканчивающиеся маленькой “e”.
3. Некоторые метапоследовательности
Некоторые паттерны используются постоянно. Для них существуют шорткаты. Вот самые часто используемые:
\w
— соответствие любой букве, цифре или подчеркиванию, эквивалентен [a-zA-Z0–9_]
.
\W
— соответствие любому символу, кроме буквенного и цифрового символа и знака подчёркивания.
\d
— соответствие любому цифровому символу, эквивалентен [0–9]
.
\D
— соответствие любому нецифровому символу.
4. Операторы “+” и “*”
Символ точки используется для поиска единичного символа. Что если нам нужно найти больше?
Символ +
используется для 1 или более значений крайнего левого символа.
Символ *
используется для 0 или более значений крайнего левого символа.
Например, если нужно найти все подстроки, начинающиеся с “d” и заканчивающиеся на “e”, нам может встретиться ноль или более символов между “d” и “e”. Используем: d\w*e
Если нужно найти все подстроки, начинающиеся с “d” и заканчивающиеся на “e” с как минимум одним символом между “d” и “e”, используем: d\w+e
Также можно применить более общий подход с добавлением “{ }”
\w{n}
— повторяет \w
ровно n раз.” выделяет начало строки, а “$” выделяет конец строки.
6. Границы слов
Вы заметили, что в примерах выше я всегда выделял подстроки, а не слова?
Что если нужно найти все слова, начинающиеся с “d”?
Можно ли использовать паттерн d\w*
? А давайте посмотрим.
Функции регулярных выражений
До сих пор мы использовали только функцию findall
из пакета re
, но он содержит значительно больше функций. Давайте рассмотрим их по очереди.
1.
findall
Мы уже применяли findall
. Ее я использую чаще всего. Давайте изучим ее детальнее.
Ввод: паттерн и тестовая строка.
Вывод: список строк.
#USAGE:
pattern = r'[iI]t'
string = "It was the best of times, it was the worst of times."
for match in matches:
print(match)
------------------------------------------------------------
It
it
2. Поиск
Ввод: паттерн и тестовая строка.
Вывод: местоположение первого совпадения объекта.
#USAGE:
pattern = r'[iI]t'
string = "It was the best of times, it was the worst of times."
location = re.search(pattern,string)
print(location)
------------------------------------------------------------
<_sre.SRE_Match object; span=(0, 2), match='It'>
Данные местоположения объекта получим, используя:
print(location.group())
------------------------------------------------------------
'It'
3. Замена
Это еще одна прекрасная функциональность. При работе с NLP иногда нужно заменить целые числа иксами или отредактировать какой-то документ. Простая функция “найти и заменить” в любом текстовом редакторе.
Ввод: паттерн поиска, паттерн замены и целевая строка
Вывод: измененная строка
string = "It was the best of times, it was the worst of times."
string = re.sub(r'times', r'life', string)
print(string)
------------------------------------------------------------
It was the best of life, it was the worst of life.
Некоторые примеры применения:
Регулярные выражения используются во многих случаях, когда нужна проверка данных. Вы наверняка видели на веб-сайтах подсказки вроде “этот адрес электронной почты не действителен”. Такая подсказка может быть написана с помощью нескольких условий if и else, но регулярные выражения в данном случае удобнее.
1. PAN номера
В Индии используются PAN номера для налоговой идентификации вместо SSN номеров в США. Основной критерий действительности PAN — все буквы должны быть заглавными, а символы должны располагаться в следующем порядке:
<char><char><char><char><char><digit><digit><digit><digit><char>
Вопрос:
‘ABcDE1234L’ — действительный PAN?
Как решается эта задача без регулярных выражений? Возможно, будет написан цикл for с индексом, проходящим через строку. [«Overview Of the existing Mumbai Suburban Railway»](http://web.archive.org/web/20080620033027/http://www.mrvc.indianrail.gov.in/overview.htm). _Official webpage of Mumbai Railway Vikas Corporation_. Archived from [the original](http://www.mrvc.indianrail.gov.in/overview.htm) on 2008-06-20<span>. Retrieved 2008-12-11</span>.</span><span title=»ctx_ver=Z39.88-2004&rfr_id=info%3Asid%2Fen.wikipedia.org%3ATrain&rft.atitle=Overview+Of+the+existing+Mumbai+Suburban+Railway&rft.genre=article&rft_id=http%3A%2F%2Fwww.mrvc.indianrail.gov.in%2Foverview.htm&rft.jtitle=Official+webpage+of+Mumbai+Railway+Vikas+Corporation&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal»><span> </span></span></span></li> </ol> </div>
А нужно найти все основные домены в тексте askoxford.com; bnsf.com; hydrogencarsnow.com; mrvc.indianrail.gov.in; web.archive.org
Как это сделать?
match=re.findall(r'http(s:|:)\/\/(www.|ww2.|)([0-9a-z.A-Z-]*\.\w{2,3})',string)
for elem in match:
print(elem)
--------------------------------------------------------------------
(':', 'www.', 'askoxford.com')
(':', 'www.', 'hydrogencarsnow.com')
(':', 'www.', 'bnsf.com')
(':', '', 'web.archive.org')
(':', 'www.', 'mrvc.indianrail.gov.in')
(':', 'www.', 'mrvc.indianrail.gov.in')
| — здесь это оператор or, который возвращает наборы, содержащие паттерн внутри ().
3. Find Email Addresses:
Вот регулярное выражение, которое ищет адрес электронной почты в тексте:
match=re.findall(r'([\w0-9-._][email protected][\w0-9-.]+[\w0-9]{2,3})',string)
Это продвинутые примеры, но их понимание поможет вам усвоить полученную информацию.
Заключение
Хотя сперва регулярные выражения могут выглядеть устрашающе, они предоставляют великолепную гибкость при манипулировании данными, создании функций и поиске паттернов.
В работе с текстовыми данными я использую их очень часто, а также включаю их в работу над проверкой данных.
Еще я большой поклонник инструмента regex101 и использую его для проверки работы регулярных выражений. Не думаю, что использовал бы регулярные выражения так часто, если бы не этот прекрасный инструмент.
Читайте также:
Перевод статьи Rahul Agarwal: The Ultimate Guide to using the Python regex module
Python Regex: re.search () VS re.findall ()
Предварительное условие: Регулярное выражение с примерами | Python
Регулярное выражение (иногда называемое выражением Rational) — это последовательность символов, определяющая шаблон поиска, в основном для использования в сопоставлении шаблонов со строками или сопоставлении строк, то есть в операциях, подобных «поиску и замене». Регулярные выражения — это обобщенный способ сопоставления шаблонов с последовательностями символов.
Модуль Регулярные выражения (RE) определяет набор строк (шаблон), который ему соответствует.Соответствует началу $ Соответствует концу . Соответствует любому символу, кроме новой строки ? Соответствует нулю или одному вхождению. | Означает ИЛИ (соответствует любому из символов разделенные им. * Любое количество вхождений (включая 0 вхождений) + Одно или несколько вхождений {} Укажите количество вхождений предыдущего RE чтобы соответствовать. () Вложить группу RE
re.search ()
re.search ()
либо возвращает None (если шаблон не совпадает), либо re.MatchObject
, который содержит информацию о совпадающей части строки. Этот метод останавливается после первого совпадения, поэтому он лучше всего подходит для проверки регулярного выражения, а не для извлечения данных.
Пример:
0200 |
Выход:
Соответствует индексу 14, 21 Полный матч: 24 июня Месяц: июнь День: 24
ре.findall ()
Возвращает все неперекрывающиеся совпадения шаблона в строке в виде списка строк. Строка просматривается слева направо, и совпадения возвращаются в найденном порядке.
Пример:
|
Вывод:
['123456789', '987654321']
Внимание компьютерщик! Укрепите свои основы с помощью курса Python Programming Foundation и изучите основы.
Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS . И чтобы начать свое путешествие по машинному обучению, присоединяйтесь к Машинное обучение — курс базового уровня
Python RegEx
Регулярное выражение или регулярное выражение — это последовательность символов, образующая шаблон поиска.
RegEx может использоваться, чтобы проверить, содержит ли строка указанный шаблон поиска.
Модуль RegEx
Python имеет встроенный пакет под названием re
, который можно использовать для работы с
Регулярные выражения.
Импорт модуля re
:
RegEx в Python
Когда вы импортировали модуль re
, вы
можно начинать использовать регулярные выражения:
Пример
Найдите строку, чтобы узнать, начинается ли она с «The» и заканчивается «Испания»:
Импортировать re txt = «Дождь в Испании»
x = re.The. * Spain $ «, txt)
Функции RegEx
Модуль re
предлагает набор функций, которые позволяют
нам искать совпадение в строке:
Функция | Описание |
---|---|
найти все | Возвращает список, содержащий все совпадения |
поиск | Возвращает объект Match, если где-либо в строке есть совпадение. |
раздельный | Возвращает список, в котором строка была разделена при каждом совпадении |
переходник | Заменяет одно или несколько совпадений строкой |
Метасимволы
Метасимволы — это символы со специальным значением:
Персонаж | Описание | Пример | Попробуй |
---|---|---|---|
[] | Набор символов | «[а-м]» | Попробуй » |
\ | Сигнализирует о специальной последовательности (также может использоваться для экранирования специальных символов) | «\ d» | Попробуй » |
.привет « | Попробуй » | ||
$ 90 259 | Заканчивается на | «мир $» | Попробуй » |
* | Ноль или более вхождений | «aix *» | Попробуй » |
+ | Одно или несколько событий | «aix +» | Попробуй » |
{} | Точно указанное количество вхождений | «аль {2}» | Попробуй » |
| | Либо или | «водопад | остаётся» | Попробуй » |
() | Захват и группировка |
Особые последовательности
Специальная последовательность — это \
, за которым следует один из символов в списке ниже, и имеет особое значение:
Персонаж | Описание | Пример | Попробуй |
---|---|---|---|
\ A | Возвращает совпадение, если указанные символы находятся в начале строка | «\ Ahe» | Попробуй » |
\ b | Возвращает совпадение, в котором указанные символы находятся в начале или в
конец слова («r» в начале означает, что строка рассматривается как «необработанная строка») | r «\ bain» r «ain \ b» | Попробовать » Попробовать» |
\ B | Возвращает совпадение, в котором указанные символы присутствуют, но НЕ в начале.
(или на
конец) слова («r» в начале гарантирует, что строка обрабатывается как «необработанная строка») | r «\ Bain» r «ain \ B» | Попробовать » Попробовать» |
\ d | Возвращает совпадение, в котором строка содержит цифры (числа от 0 до 9) | «\ d» | Попробуй » |
\ D | Возвращает совпадение, в котором строка НЕ содержит цифр | «\ D» | Попробуй » |
\ с | Возвращает совпадение, в котором строка содержит символ пробела | «\ s» | Попробуй » |
\ S | Возвращает совпадение, в котором строка НЕ содержит пробела | «\ S» | Попробуй » |
\ w | Возвращает совпадение, в котором строка содержит любые символы слова (символы из от a до Z, цифры от 0 до 9 и символ подчеркивания _) | «\ w» | Попробуй » |
\ Вт | Возвращает совпадение, в котором строка НЕ содержит символов слова | «\ Вт» | Попробуй » |
\ Z | Возвращает совпадение, если указанные символы находятся в конце строки | «Испания \ Z» | Попробуй » |
Наборы
Набор — это набор символов в квадратных скобках []
со специальным значением:
Комплект | Описание | Попробуй |
---|---|---|
[arn] | Возвращает совпадение, в котором один из указанных символов ( a , r или n ) являются
подарок | Попробуй » |
[ан-н] | Возвращает совпадение для любого символа нижнего регистра в алфавитном порядке между a и n | Попробуй » |
[^ arn] | Возвращает совпадение для любого символа, ЗА ИСКЛЮЧЕНИЕМ a , r и n | Попробуй » |
[0123] | Возвращает совпадение, в котором любая из указанных цифр ( 0 , 1 , 2 или 3 ) являются
подарок | Попробуй » |
[0-9] | Возвращает совпадение для любой цифры между 0 и 9 | Попробуй » |
[0-5] [0-9] | Возвращает совпадение для любых двузначных чисел из 00 и 59 | Попробуй » |
[a-zA-Z] | Возвращает совпадение для любого символа в алфавитном порядке между a и z , нижний регистр ИЛИ верхний регистр | Попробуй » |
[+] | В наборах, + , * , . , | , г. () , $ , {} не имеет особого значения, поэтому [+] означает: вернуть совпадение для любого + символ в строке | Попробуй » |
Функция findall ()
Функция findall ()
возвращает список, содержащий все совпадения.
Пример
Распечатать список всех совпадений:
import re txt = «Дождь в Испании»
x = re.findall («ай»,
txt)
печать (x)
Список содержит совпадения в порядке их нахождения.
Если совпадений не найдено, возвращается пустой список:
Пример
Вернуть пустой список, если совпадений не найдено:
import re txt = «Дождь в Испании»
x = re.findall («Португалия»,
txt)
печать (x)
Функция поиска ()
Функция search ()
ищет строку
для совпадения и возвращает объект Match, если есть
матч.
Если есть более одного совпадения, будет возвращено только первое совпадение:
Пример
Поиск первого символа пробела в строке:
import re txt = «Дождь в Испании»
x = re.search («\ s»,
txt)
print («Первый пробел находится в позиция: «, x.start ())
Попробуй сам » Если совпадений не найдено, возвращается значение Нет
:
Пример
Выполните поиск, который не дал совпадений:
import re txt = «Дождь в Испании»
x = re.search («Португалия»,
txt)
печать (x)
Функция split ()
Функция split ()
возвращает список, в котором
строка была разделена при каждом совпадении:
Пример
Разделить на каждый символ пробела:
import re txt = «Дождь в Испании»
x = re.split («\ s»,
txt)
печать (x)
Вы можете контролировать количество вхождений, указав макссплит
параметр:
Пример
Разделить строку только при первом появлении:
import re txt = «Дождь в Испании»
x = re.split («\ s»,
текст,
1)
печать (x)
Функция sub ()
Функция sub ()
заменяет совпадения на
текст на ваш выбор:
Пример
Замените каждый символ пробела числом 9:
import re txt = «Дождь в Испании»
x = re.sub («\ s»,
«9», txt)
печать (x)
Вы можете контролировать количество замен, указав количество
параметр:
Пример
Заменить первые 2 вхождения:
import re txt = «Дождь в Испании»
x = re.sub («\ s»,
«9», txt, 2)
печать (x)
Match Object
Match Object — это объект, содержащий информацию о поиске и результате.
Примечание: Если совпадений нет, значение Нет
будет
возвращается вместо Match Object.
Пример
Выполните поиск, который вернет объект соответствия:
import re txt = «Дождь в Испании»
x = re.поиск («ай»,
txt)
print (x) # это напечатает объект
Объект Match имеет свойства и методы, используемые для получения информации. о поиске, и результат:
.span ()
возвращает кортеж, содержащий начальную и конечную позиции совпадения.
.string
возвращает строку, переданную в функцию
. Group ()
возвращает часть строки, в которой было совпадение
Пример
Распечатайте позицию (начало и конец) первого совпадения.
Регулярное выражение ищет любые слова, начинающиеся с верхнего регистра. «S»:
import re txt = «Дождь в Испании»
x = re.search (r «\ bS \ w +», txt)
печать ( x.span () )
Пример
Вывести строку, переданную в функцию:
import re txt = «Дождь в Испании»
x = re.search (r «\ bS \ w +», txt)
печать ( x.string )
Пример
Вывести часть строки, в которой обнаружено совпадение.
Регулярное выражение ищет любые слова, начинающиеся с верхнего регистра. «S»:
import re txt = «Дождь в Испании»
x = re.search (r «\ bS \ w +», txt)
печать ( x.group () )
Примечание: Если совпадений нет, значение Нет
будет
возвращается вместо Match Object.
Python re.findall () — все, что вам нужно знать
Когда я впервые узнал о регулярных выражениях, я не особо оценил их силу.Но есть причина, по которой регулярных выражений пережили семь десятилетий технологических прорывов : программисты, которые понимают регулярные выражения, имеют огромное преимущество при работе с текстовыми данными. Они могут написать в одной строчке кода то, на что у других уйдут десятки!
Эта статья посвящена методу findall ()
библиотеки Python re
. Метод findall ()
— это самый простой способ использования регулярных выражений в Python: если вы хотите их освоить, начните здесь!
Статья по теме: Python Regex Superpower — The Ultimate Guide
Хотите освоить суперсилу регулярных выражений? Посмотрите мою новую книгу Самый разумный способ изучения регулярных выражений в Python с инновационным трехэтапным подходом для активного обучения: (1) изучите главу книги, (2) решите головоломку с кодом и (3) ) посмотрите обучающее видео с главой.
Так как же работает метод re.findall ()
? Изучим спецификацию.
Как работает метод findall () в Python?
Метод re.findall (шаблон, строка)
сканирует строку
от слева направо , ища все неперекрывающихся совпадений шаблона
. Он возвращает список строк в соответствующем порядке при сканировании строки слева направо.
Спецификация :
re.findall (pattern, string, flags = 0)
Метод re.findall ()
имеет до трех аргументов.
-
шаблон
: шаблон регулярного выражения, которому вы хотите сопоставить. -
строка
: строка, в которой вы хотите найти шаблон. -
flags
(необязательный аргумент): более продвинутый модификатор, позволяющий настраивать поведение функции. Хотите знать, как использовать эти флаги? Прочтите эту подробную статью в блоге Finxter.
Рассмотрим каждый из них подробнее.
Возвращаемое значение:
Метод re.findall ()
возвращает список строк. Каждый строковый элемент является соответствующей подстрокой строкового аргумента.
Давайте посмотрим на несколько примеров!
Примеры re.findall ()
Импортируйте модуль re
и создайте текстовую строку для поиска шаблонов регулярных выражений:
import re текст = '' ' Ха! позвольте мне увидеть ее: увы! ему холодно: Кровь у нее отстоялась, суставы затекли; Жизнь и эти губы давно разлучены: Смерть лежит на ней, как безвременный мороз На самый сладкий цветок на всем поле.'' '
Допустим, вы хотите найти в тексте строку ' her '
:
>>> re.findall (' her ', text) ['она', 'она', 'она']
Первый аргумент — это шаблон, который вы ищете. В нашем случае это строка «ее»
. Второй аргумент — это анализируемый текст. Вы сохранили многострочную строку в переменной text
— поэтому вы принимаете ее как второй аргумент. Вам не нужно определять необязательный третий аргумент flags
метода findall ()
, потому что в этом случае вас устраивает поведение по умолчанию.
Также обратите внимание, что функция findall ()
возвращает список всех совпадающих подстрок. В этом случае это может быть не слишком полезно, потому что мы искали только точную строку. Но если мы ищем более сложные шаблоны, это может быть очень полезно:
>>> re.findall ('\\ bf \ w + \\ b', text) ['мороз', 'цветок', 'поле']
Регулярное выражение '\\ bf \ w + \\ b'
соответствует всем словам, начинающимся с символа 'f'
.
Вы можете спросить: зачем заключать регулярное выражение в начало и конец '\\ b'
? Это символ границы слова, который соответствует пустой строке в начале или в конце слова.Вы можете определить слово как последовательность символов, которые не являются пробелами или другими разделителями, например '.:,?!'
.
В предыдущем примере вам нужно снова экранировать граничный символ '\ b'
, потому что в строке Python значением по умолчанию для последовательности символов '\ b'
является символ обратной косой черты.
В чем разница между re.findall () и re.search ()?
Есть два различия между re.findall (шаблон, строка)
и re.search (шаблон, строка)
методы:
-
re.search (шаблон, строка)
возвращает объект соответствия, аre.findall (шаблон, строка)
возвращает список совпадающих строк. -
re.search (шаблон, строка)
возвращает только первое совпадение в строке, аre.findall (шаблон, строка)
возвращает все совпадения в строке.
И то, и другое можно увидеть в следующем примере:
>>> text = 'Python превосходит Python' >>> ре.search ('Py ... n', текст) <объект re.Match; span = (0, 6), match = 'Python'> >>> re.findall ('Py ... n', текст) ['Python', 'Python']
Строка «Python превосходит Python»
содержит два вхождения «Python»
. Метод search ()
возвращает только объект соответствия первого вхождения. Метод findall ()
возвращает список всех вхождений.
В чем разница между re.findall () и re.match ()?
Между re есть два отличия.findall (шаблон, строка)
и методы re.match (шаблон, строка)
:
-
re.match (шаблон, строка)
возвращает объект соответствия, аre.findall (шаблон, строка)
возвращает список совпадающих строк. -
re.match (шаблон, строка)
возвращает только первое совпадение в строке — и только в начале — в то время какre.findall (шаблон, строка)
возвращает все совпадения в строке.
И то, и другое можно увидеть в следующем примере:
>>> text = 'Python превосходит Python' >>> ре.match ('Py ... n', текст) <объект re.Match; span = (0, 6), match = 'Python'> >>> re.findall ('Py ... n', текст) ['Python', 'Python']
Строка «Python превосходит Python»
содержит два вхождения «Python»
. Метод match ()
возвращает только объект соответствия первого вхождения. Метод findall ()
возвращает список всех вхождений.
Куда идти дальше?
В этой статье представлена модель re.findall (pattern, string)
, который пытается сопоставить все вхождения шаблона регулярного выражения в заданной строке и возвращает список всех совпадений в виде строк.
Python быстро растет, и мир все больше и больше делится на два класса: тех, кто понимает кодирование, и тех, кто этого не делает. Последним будет все труднее участвовать в эпоху массового принятия и распространения цифрового контента. Вы хотите ежедневно улучшать свои навыки Python, не тратя много времени?
Тогда присоединяйтесь к моему списку рассылки «Coffee Break Python», состоящему из десятков тысяч амбициозных программистов!
Инженеры Google — мастера регулярных выражений. Поисковая система Google — это массивная машина обработки текста , которая извлекает ценность из триллионов веб-страниц.
Инженеры Facebook — мастера регулярных выражений. Социальные сети, такие как Facebook, WhatsApp и Instagram, связывают людей с помощью текстовых сообщений .
Инженеры Amazon — мастера регулярных выражений. Гиганты электронной коммерции поставляют товары на основе текстовых описаний товаров .Регулярные выражения управляют игрой, когда обработка текста встречается с информатикой.
Если вы тоже хотите стать мастером регулярных выражений, ознакомьтесь с самым полным курсом регулярных выражений Python на планете:
Работая исследователем в распределенных системах, доктор Кристиан Майер обнаружил свою любовь к обучению на компьютере. студенты естественных наук.
Чтобы помочь студентам достичь более высокого уровня успеха в Python, он основал веб-сайт по обучению программированию Finxter.com. Он является автором популярной книги по программированию Python One-Liners (NoStarch 2020), соавтором серии самоизданных книг о Python для кофе-брейков, энтузиаст информатики, фрилансер и владелец одного из 10 крупнейших блогов Python по всему миру.
Его страстью являются письмо, чтение и кодирование. Но его самая большая страсть — служить начинающим программистам через Finxter и помогать им повышать свои навыки. Вы можете присоединиться к его бесплатной электронной академии здесь.
На этой странице: re module, re.findall (), re.sub (), re.compile (), re.search (), re.search (). group ().Re ModuleИтак, вы узнали все о регулярных выражениях и готовы использовать их в Python. Давайте приступим к делу! Модуль re — это стандартная библиотека Python, которая обрабатывает все, что связано с регулярными выражениями. Как и любой другой модуль, вы начинаете с его импорта.Поиск всех совпадений в строкеПредположим, вы хотите найти все слова, начинающиеся с «wo» в этом очень коротком тексте ниже. Вы хотите использовать re.findall () метод. Он принимает два аргумента: (1) шаблон регулярного выражения и (2) целевая строка для поиска совпадений.
Вернуться к re.findall (). Он возвращает все совпавшие части строки в виде списка. Если совпадений нет, он просто вернет пустой список:
Подстановка всех совпадений в строкуЧто, если вы хотите заменить все совпадающие части чем-то другим? Это можно сделать с помощью метода re.sub (). Ниже мы находим все последовательности гласных и заменяем их на ‘-‘.Метод возвращает результат в виде новой строки.
Компиляция объекта регулярного выраженияЕсли вам нужно сопоставить регулярное выражение с множеством разных строк, рекомендуется создать регулярное выражение как объект Python. Таким образом, конечный автомат для регулярного выражения компилируется один раз и используется повторно.Поскольку построение FSA является довольно затратным с точки зрения вычислений, это снижает нагрузку на обработку. Для этого воспользуйтесь методом re.compile ():
Проверка наличия совпаденияИногда нас интересует только подтверждение, есть ли совпадение в данной строке.Для этого re.findall () является излишним, потому что он сканирует всю строку для получения * каждой * подходящей подстроки. Это нормально, когда вы имеете дело с несколькими короткими строками, как мы здесь, но в реальном мире ваши строки могут быть намного длиннее и / или вы будете выполнять сопоставление тысячи или даже миллионы раз, поэтому разница складывается.В этом контексте хорошей альтернативой является re.search (). Этот метод находит только первое совпадение и затем завершает работу. Если совпадение найдено, возвращается «объект совпадения».Но если нет, возвращает … ничего . Ниже r’e + ‘успешно сопоставляется в строке «Бесцветный …», поэтому возвращается соответствующий объект. Как ни странно, в нашем дереве нет ни одной буквы «е», поэтому тот же поиск ничего не возвращает.
| абс | Нет совпадений |
псевдоним | Матч | |
бездна | Матч | |
Псевдоним | Нет совпадений | |
Счеты | Нет совпадений |
Python имеет модуль с именем re
для работы с RegEx. a…s $ ‘
test_string = ‘бездна’
результат = re.match (шаблон, тестовая_строка) если результат:
print («Успешный поиск.»)
еще:
print («Поиск не увенчался успехом.»)
Здесь мы использовали функцию re.match ()
для поиска шаблона в test_string . Метод возвращает объект соответствия, если поиск успешен. В противном случае возвращается Нет
.
Есть несколько других функций, определенных в модуле re для работы с RegEx. $ * + ? {} () \ |
[]
— Квадратные скобки
Квадратные скобки обозначают набор символов, которые вы хотите сопоставить.
Выражение | Строка | Совпадает? |
---|---|---|
[abc] | a | 1 совпадение |
ac | 2 совпадения | |
Привет, Джуд | Нет совпадений | |
abc de ca | 5 совпадений |
Здесь [abc]
будет соответствовать, если строка, которую вы пытаетесь сопоставить, содержит любое из a
, b
или c
. используется для проверки, начинается ли строка с определенного символа.ab
abc
акб
a
, но не сопровождается b
) $
— Доллар
Символ доллара $
используется для проверки, заканчивается ли строка определенным символом .
Выражение | Строка | Совпадает? |
---|---|---|
a долл. США | a | 1 совпадение |
формула | 1 совпадение | |
кабина | Нет совпадений |
*
— Звезда
Звездочка *
соответствует нулю или более вхождений оставшегося образца.
Выражение | Строка | Совпадает? |
---|---|---|
ма * н | мин | 1 совпадение |
человек | 1 совпадение | |
maaan | 1 совпадение | |
основной | Нет совпадений (за a не следует n ) | |
женщина | 1 совпадение |
+
— Плюс
Символ «плюс» +
соответствует одному или нескольким экземплярам оставшегося образца.
Выражение | Строка | Совпадает? |
---|---|---|
ма + н | мин | Нет совпадений (нет символ ) |
человек | 1 совпадение | |
maaan | 1 совпадение | |
основной | Нет совпадений (за a не следует n) | |
женщина | 1 совпадение |
?
– Вопросительный знак
Знак вопроса ?
соответствует нулю или одному вхождению оставшегося образца.
Выражение | Строка | Совпадает? |
---|---|---|
ма? Н | мин | 1 совпадение |
человек | 1 совпадение | |
maaan | Нет совпадений (более одного символа a ) | |
основной | Нет совпадений (за a не следует n) | |
женщина | 1 совпадение |
{}
— Раскосы
Рассмотрим этот код: {n, m}
.Это означает, что ему осталось не менее n и не более m повторений шаблона.
Выражение | Строка | Совпадает? |
---|---|---|
a {2,3} | abc dat | Нет совпадений |
abc daat | 1 совпадение (при d aa t ) | |
aabc daaat | 2 совпадения (на aa bc и d aaa t ) | |
aabc daaaat | 2 совпадения (на aa bc и d aaa на ) |
Попробуем еще один пример.Это RegEx [0-9] {2, 4}
соответствует как минимум 2 цифрам, но не более 4 цифрам
Выражение | Строка | Совпадает? |
---|---|---|
[0-9] {2,4} | ab123csde | 1 совпадение (совпадение в ab 123 csde ) |
12 и 345673 | 3 совпадения ( 12 , 3456 , 73 ) | |
1 и 2 | Нет совпадений |
|
— Чередование
Вертикальная полоса |
используется для чередования (оператор или
).
Выражение | Строка | Совпадает? |
---|---|---|
a | b | код | Нет совпадений |
аде | 1 совпадение (совпадение по номеру a de ) | |
acdbea | 3 совпадения (на a cd b e a ) |
Здесь a | b
соответствует любой строке, содержащей либо a , либо b
()
— Группа
Круглые скобки ()
используются для группировки подшаблонов.Например, (a | b | c) xz
соответствует любой строке, которая соответствует a или b или c , за которым следует xz
Выражение | Строка | Совпадает? |
---|---|---|
(a | b | c) xz | ab xz | Нет совпадений |
abxz | 1 совпадение (совпадение в a bxz ) | |
axz cabxz | 2 совпадения (на axz bc ca bxz ) |
\
— Обратная косая черта
Люфт \
используется для экранирования различных символов, включая все метасимволы.Например,
\ $ соответствует
, если строка содержит $
, за которым следует a
. Здесь $
не интерпретируются механизмом RegEx особым образом.
Если вы не уверены, имеет ли символ особое значение, вы можете поставить перед ним \
. Это гарантирует, что с персонажем не будут обращаться особым образом.
Особые последовательности
Специальные последовательности упрощают написание часто используемых шаблонов.Вот список специальных последовательностей:
\ A
— Соответствует, если указанные символы находятся в начале строки.
Выражение | Строка | Совпадает? |
---|---|---|
\ Athe | солнце | Матч |
На солнце | Нет совпадений |
\ b
— Соответствует, если указанные символы находятся в начале или в конце слова.
Выражение | Строка | Совпадает? |
---|---|---|
\ bfoo | футбол | Матч |
футбольный мяч | Матч | |
Футбольный мяч | Нет совпадений | |
foo \ b | Foo | Матч |
тест afoo | Матч | |
самый быстрый | Нет совпадений |
\ B
— Напротив \ b
.Соответствует указанным символам , а не в начале или конце слова.
Выражение | Строка | Совпадает? |
---|---|---|
\ Bfoo | футбол | Нет совпадений |
футбольный мяч | Нет совпадений | |
Футбольный мяч | Матч | |
foo \ B | Foo | Нет совпадений |
тест afoo | Нет совпадений | |
самый быстрый | Матч |
\ d
— соответствует любой десятичной цифре. 0-9]
Выражение | Строка | Совпадает? |
---|---|---|
\ D | 1ab34 "50 | 3 совпадения (в 1 ab 34 " 50 ) |
1345 | Нет совпадений |
\ s
— соответствует, где строка содержит любой символ пробела.Эквивалент [\ t \ n \ r \ f \ v]
.
Выражение | Строка | Совпадает? |
---|---|---|
\ с | Python RegEx | 1 совпадение |
PythonRegEx | Нет совпадений |
\ S
— соответствует, где строка содержит любой непробельный символ. \ t \ n \ r \ f \ v] .
Выражение | Строка | Совпадает? |
---|---|---|
\ S | а б | 2 совпадения (на a b ) |
| Нет совпадений |
\ w
— соответствует любому буквенно-цифровому символу (цифрам и алфавитам). Эквивалент [a-zA-Z0-9_]
.Кстати, подчеркивание _
также считается буквенно-цифровым символом.
Выражение | Строка | Совпадает? |
---|---|---|
\ w | 12 & ":; c | 3 совпадения (на 12 & ":; c ) |
% ">! | Нет совпадений |
\ W
— соответствует любому не буквенно-цифровому символу.a-zA-Z0-9_]
Выражение | Строка | Совпадает? |
---|---|---|
\ W | 1a2% c | 1 совпадение (на 1 a 2 % c ) |
Python | Нет совпадений |
\ Z
— соответствует, если указанные символы находятся в конце строки.
Выражение | Строка | Совпадает? |
---|---|---|
Python \ Z | Мне нравится Python | 1 совпадение |
Мне нравится программирование на Python | Нет совпадений | |
Python - это весело. | Нет совпадений |
Совет: Для создания и тестирования регулярных выражений вы можете использовать инструменты тестера RegEx, такие как regex101. Этот инструмент не только помогает вам создавать регулярные выражения, но и помогает вам их изучить.
Теперь вы понимаете основы RegEx, давайте обсудим, как использовать RegEx в вашем коде Python.
Python RegEx
Python имеет модуль re
для работы с регулярными выражениями.Чтобы использовать его, нам нужно импортировать модуль.
импорт повторно
Модуль определяет несколько функций и констант для работы с RegEx.
re.findall ()
Метод re.findall ()
возвращает список строк, содержащих все совпадения.
Пример 1: re.findall ()
# Программа для извлечения чисел из строки
импорт ре
string = 'привет 12 привет 89. Привет 34'
шаблон = '\ d +'
результат = re.findall (шаблон, строка)
печать (результат)
# Вывод: ['12', '89', '34']
Если шаблон не найден, re.findall ()
возвращает пустой список.
re.split ()
Метод re.split
разбивает строку, в которой есть совпадение, и возвращает список строк, в которых произошло разбиение.
Пример 2: re.split ()
импорт ре
string = 'Двенадцать: 12 Восемьдесят девять: 89.'
шаблон = '\ d +'
результат = re.split (шаблон, строка)
печать (результат)
# Вывод: ['Двенадцать:', 'Восемьдесят девять:', '.']
Если шаблон не найден, re.split ()
возвращает список, содержащий исходную строку.
Вы можете передать аргумент maxsplit
методу re.split ()
. Это максимальное количество разбиений, которое может произойти.
импорт ре
string = 'Двенадцать: 12 Восемьдесят девять: 89 Девять: 9.'
шаблон = '\ d +'
# maxsplit = 1
# разделить только при первом вхождении
результат = re.split (шаблон, строка, 1)
печать (результат)
# Вывод: ['Двенадцать:', 'Восемьдесят девять: 89 Девять: 9.']
Кстати, значение по умолчанию maxsplit
равно 0; имея в виду все возможные расколы.
re.sub ()
Синтаксис re.sub ()
:
re.sub (шаблон, замена, строка)
Метод возвращает строку, в которой совпавшие вхождения заменяются содержимым переменной replace .
Пример 3: re.sub ()
# Программа для удаления всех пробелов
импорт ре
# многострочная строка
строка = 'abc 12 \
de 23 \ n f45 6 '
# соответствует всем пробельным символам
шаблон = '\ s +'
# пустая строка
заменить = ''
new_string = re.sub (шаблон, замена, строка)
печать (новая_строка)
# Вывод: abc12de23f456
Если шаблон не найден, re.sub ()
возвращает исходную строку.
Вы можете передать count в качестве четвертого параметра методу re.sub ()
. Если опущено, результат будет 0. Это заменит все вхождения.
импорт ре
# многострочная строка
строка = 'abc 12 \
de 23 \ n f45 6 '
# соответствует всем пробельным символам
шаблон = '\ s +'
заменить = ''
new_string = re.sub (r '\ s +', заменить, строка, 1)
печать (новая_строка)
# Выход:
# abc12de 23
# f45 6
re.subn ()
re.subn ()
аналогичен re.sub ()
, за исключением того, что он возвращает кортеж из 2 элементов, содержащий новую строку и количество сделанных замен.
Пример 4: re.subn ()
# Программа для удаления всех пробелов
импорт ре
# многострочная строка
строка = 'abc 12 \
de 23 \ n f45 6 '
# соответствует всем пробельным символам
шаблон = '\ s +'
# пустая строка
заменить = ''
new_string = re.subn (шаблон, заменить, строка)
печать (новая_строка)
# Вывод: ('abc12de23f456', 4)
re.search ()
Метод re.search ()
принимает два аргумента: шаблон и строку. Метод ищет первое место, где шаблон RegEx соответствует строке.
Если поиск успешен, re.search ()
возвращает объект соответствия; в противном случае возвращается Нет
.
match = re.search (шаблон, строка)
Пример 5: re.поиск ()
импорт ре
string = "Python - это весело"
# проверяем, стоит ли Python в начале
match = re.search ('\ APython', строка)
если совпадение:
print ("шаблон найден внутри строки")
еще:
print («шаблон не найден»)
# Вывод: образец найден внутри строки
Здесь match содержит объект соответствия.
Сопоставить объект
Вы можете получить методы и атрибуты объекта соответствия с помощью функции dir ().
Некоторые из наиболее часто используемых методов и атрибутов объектов сопоставления:
матч.группа ()
Метод group ()
возвращает часть строки, в которой есть совпадение.
Пример 6: сопоставить объект
импорт ре
строка = '39801 356, 2102 1111'
# Трехзначное число, за которым следует пробел, за которым следует двузначное число
шаблон = '(\ d {3}) (\ d {2})'
# Переменная соответствия содержит объект Match.
match = re.search (шаблон, строка)
если совпадение:
печать (match.group ())
еще:
print («шаблон не найден»)
# Вывод: 801 35
Здесь match переменная содержит объект соответствия.
Наш шаблон (\ d {3}) (\ d {2})
имеет две подгруппы: (\ d {3})
и (\ d {2})
. Вы можете получить часть строки этих подгрупп в скобках. Вот как:
>>> match.group (1)
'801'
>>> match.group (2)
'35'
>>> match.group (1, 2)
('801', '35')
>>> match.groups ()
('801', '35')
match.start (), match.end () и match.span ()
Функция start ()
возвращает индекс начала сопоставленной подстроки.Точно так же end ()
возвращает конечный индекс сопоставленной подстроки.
>>> match.start ()
2
>>> match.end ()
8
Функция span ()
возвращает кортеж, содержащий начальный и конечный индексы совпадающей части.
>>> match.span ()
(2, 8)
match.re и match.string
Атрибут re
сопоставленного объекта возвращает объект регулярного выражения. Точно так же атрибут string
возвращает переданную строку.
>>> match.re
re.compile ('(\\ d {3}) (\\ d {2})')
>>> match.string
'39801 356, 2102 1111'
Мы рассмотрели все часто используемые методы, определенные в модуле re
. Если вы хотите узнать больше, посетите модуль Python 3 re.
Использование префикса r перед RegEx
Если перед регулярным выражением используется префикс r или R , это означает необработанную строку. Например, '\ n'
— это новая строка, тогда как r '\ n'
означает два символа: обратная косая черта \
, за которой следует n
.
Люфт \
используется для экранирования различных символов, включая все метасимволы. Однако использование префикса r делает \
нормальным символом.
Пример 7: Необработанная строка с префиксом r
импорт ре
string = '\ n и \ r - escape-последовательности.'
result = re.findall (r '[\ n \ r]', строка)
печать (результат)
# Вывод: ['\ n', '\ r']
Работа с согласованными порциями — Python re (gex)?
Увидев несколько функций, которые могут соответствовать разному тексту, вы научитесь извлекать эти совпадающие части и работать с ними в этой главе.Сначала вы подробно узнаете об объекте re.Match
. А затем вы узнаете о функциях re.findall
и re.finditer
, чтобы получить все совпадения, а не только первое совпадение. Вы также узнаете несколько приемов, таких как использование функций в разделе замены re.sub
и использование функции re.subn
.
Функции re.search
и re.fullmatch
возвращают объект re.Match
, из которого могут быть извлечены различные детали, такие как согласованная часть строки, расположение согласованной части и т. Д.Обратите внимание, что вы получаете подробную информацию только о первом совпадении, несколько совпадений вы увидите позже в этой главе. Вот пример вывода re.Match
.
>>> re.search (r'ab * c ',' abc ac adc abbbc ')
& Объект LTre.Match; span = (0, 3), match = 'abc'>
>>> re.fullmatch (r'1 (2 | 3) * 4 ',' 1233224 ')
& Объект LTre.Match; span = (0, 7), match = '1233224'>
Подробная информация в выходных данных выше предназначена только для быстрого ознакомления. Есть методы и атрибуты, которые вы можете применить к re.Сопоставьте объект
, чтобы получить только точную информацию, которая вам нужна. Используйте метод span
, чтобы получить индексы , начиная с и , заканчивая + 1 соответствующей части.
>>> предложение = 'это выдумка'
>>> m = re.search (r'q. *? t ', предложение)
>>> m.span ()
(8, 12)
>>> m.span () [0]
8
# вы также можете напрямую использовать метод без использования промежуточной переменной
>>> re.search (r'q. *? t ', предложение) .span ()
(8, 12)
Группировка ()
также известна как группа захвата .Он имеет множество применений, одно из которых — возможность работать с совпадающими частями этих групп. Когда группы захвата используются с re.search
или re.fullmatch
, их можно получить с помощью метода index или group
на объекте re.Match
. Первым элементом всегда является вся согласованная часть, а остальные элементы предназначены для групп захвата, если они есть. Крайний левый (
в шаблоне получит номер группы 1
, второй крайний левый (
получит номер группы 2
и так далее.Используйте метод groups
, чтобы получить кортеж, состоящий только из частей группы захвата.
>>> re.search (r'b. * D ',' abc ac adc abbbc ')
& Объект LTre.Match; span = (1, 9), match = 'bc ac ad'>
# получение всей совпавшей части с помощью индекса
>>> re.search (r'b. * d ',' abc ac adc abbbc ') [0]
'bc ac ad'
# получение всей совпавшей части с помощью метода 'group'
# вы также можете пропустить передачу '0', так как это значение по умолчанию
>>> re.search (r'b. * d ',' abc ac adc abbbc '). group (0)
'bc ac ad'
# пример группы захвата
>>> м = ре.fullmatch (r'a (. *?) (. *) d (. *) c ',' abc ac adc abbbc ')
# чтобы получить совпадающую часть второй группы захвата, также можно использовать m.group (2)
>>> м [2]
'ac a'
# чтобы получить совпадающую часть третьей и первой групп захвата
>>> m.group (3, 1)
('c abbb', 'bc')
# чтобы получить кортеж всех групп захвата
# обратите внимание, что это не будет иметь всю совпадающую часть
>>> m.groups ()
('bc', 'ac a', 'c abbb')
Чтобы получить совпадающие местоположения для групп захвата, передайте номер группы в метод span
.Вы также можете использовать методы start
и end
для получения любого из этих местоположений. Передача 0
необязательна, если вам нужна информация для всей согласованной части.
>>> m = re.search (r'w (. *) Me ',' круто ')
>>> m.span ()
(1, 7)
>>> м. пролет (1)
(2, 5)
>>> m.start ()
1
>>> m.end (1)
5
Доступно еще много методов и атрибутов. Подробнее см. Docs.python: Match Objects.
>>> pat = re.compile (r'hi. * Bye ')
>>> m = pat.search ('Тогда до свидания', 1, 15)
>>> m.pos
1
>>> m.endpos
15
>>> м.ре
re.compile ('привет. * пока')
>>> m.string
"Тогда до свидания"
groupdict Метод
будет рассмотрен в разделе Именованные группы захвата, а метод expand
будет рассмотрен в разделе Match.expand.
С тех пор, как Python 3.8 представил выражения присваивания, стало проще работать с согласованными частями в условных операторах.
# выводить содержимое группы захвата, только если шаблон совпадает
>>> если m: = re.search (r '(. *) s', 'oh!'):
... печать (m [1])
...
>>> если m: = re.search (r '(. *) s', 'awesome'):
... печать (m [1])
...
трепет
Это часто возникает при обработке текстового файла, и инструкции зависят от того, какой шаблон соответствует.
>>> text = ['type: fruit', 'date: 2020/04/28']
>>> для ip в тексте:
... если m: = re.search (r'type: (.*) ', ip):
... печать (m [1])
... elif m: = re.search (r'date: (. *?) / (. *?) / ', ip):
... print (f'month: {m [2]}, год: {m [1]} ')
...
фрукты
месяц: 04, год: 2020
Знаете ли вы, что PEP 572 использует модуль
re
как один из примеров выражений присваивания?
Функции могут использоваться в разделе замены re.sub
вместо строки. Объект re.Match
будет передан функции в качестве аргумента. В разделе «Обратная ссылка» вы также узнаете, как напрямую ссылаться на совпадающие части в разделе замены.4 — С * 9 ‘
Обратите внимание, что вывод функции должен быть строкой, иначе вы получите сообщение об ошибке. Вы увидите больше примеров с лямбда
и определяемыми пользователем функциями в следующих разделах (например, см. Раздел «Числовые диапазоны»).
Используя функцию в разделе замены, вы можете указать переменную dict
для определения строки замены на основе совпадающего текста.
# однозначное сопоставление
>>> d = {'1': 'один', '2': 'два', '4': 'четыре'}
>>> ре.sub (r'1 | 2 | 4 ', лямбда m: d [m [0]],' 12 ')
'9two3four0onetwo'
# если совпадающий текст не существует в качестве ключа, будет использоваться значение по умолчанию
# позже вы узнаете гораздо более простой способ указать все цифры
>>> re.sub (r'0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ', лямбда m: d.get (m [0],' X '),' 12 ' )
'XtwoXfourXonetwo'
Для замены двух или более частей без использования промежуточного результата рекомендуется использовать объект dict
. b’: ‘4’} # сортируем ключи для обработки правил приоритета
>>> слова = отсортировано (d.б) ‘)
‘3 1 контакт 2 (4)’
Если у вас тысячи пар ключ-значение, настоятельно рекомендуется использовать специализированные библиотеки, такие как github: flashtext, вместо регулярных выражений.
Функция re.findall
возвращает все совпавшие части в виде списка строк.
re.findall (шаблон, строка, флаги = 0)
Первый аргумент — это шаблон RE, который вы хотите протестировать и извлечь из входной строки, которая является вторым аргументом. flags
не является обязательным. Вот несколько примеров.
>>> re.findall (r'ab * c ',' abc ac adc abbbc ')
['abc', 'ac', 'abbbc']
>>> re.findall (r'ab + c ',' abc ac adc abbbc ')
['abc', 'abbbc']
>>> s = 'ЯВНАЯ ЗАПАСНАЯ ЧАСТЬ ПАРАМЕТРА ЛОНЖЕРА'
>>> re.findall (r '\ bs? pare? \ b', s, flags = re.I)
['PAR', 'spar', 'SpArE', 'pare']
Это полезно также для целей отладки, например, для просмотра потенциальных совпадений перед применением подстановки.
>>> re.findall (r't. * A ',' это выдуманная сказка ')
['это выдумка']
>>> re.findall (r't. *? a ',' это выдумка ')
['tha', 't is a', 'ted ta']
Наличие групп захвата влияет на re.findall
по-разному в зависимости от количества используемых групп.
- Если используется одна группа захвата, выводом будет список строк. У каждого элемента будет только часть, соответствующая группе захвата.
- Если используется более одной группы захвата, на выходе будет список кортежей.Каждый элемент будет кортежем, содержащим части, соответствующие всем группам захвата
В обоих случаях любой шаблон вне групп захвата не будет представлен в выходных данных. Кроме того, вы получите пустую строку, если конкретная группа захвата не соответствует ни одному символу.
# без групп захвата
>>> re.findall (r'ab * c ',' abc ac adc abbc xabbbcz bbb bc abbbbbc ')
['abc', 'ac', 'abbc', 'abbbc', 'abbbbbc']
# с одной группой захвата
>>> re.findall (r'a (b *) c ',' abc ac adc abbc xabbbcz bbb bc abbbbbc ')
['b', '', 'bb', 'bbb', 'bbbbb']
# несколько групп захвата
# обратите внимание, что последняя дата не совпала, потому что в конце нет запятой
# позже вы узнаете, как лучше сопоставить такие шаблоны
>>> ре.findall (r '(. *?) / (. *?) / (. *?),', '2020/04 / 25,1986 / Mar / 02,77 / 12/31')
[('2020', '04', '25'), ('1986', 'март', '02')]
См. Раздел «Группы без захвата», если вам нужно использовать группировки, не влияя на вывод re.findall
.
Используйте re.finditer
, чтобы получить объект-итератор с каждым элементом как re.Match
объектов для каждой согласованной части.
re.finditer (pattern, string, flags = 0)
# вывод finditer является объектом итератора
>>> ре.finditer (r'ab + c ',' abc ac adc abbbc ')
& Объект LTcallable_iterator в 0x7fb65e103438>
# каждый элемент является объектом re.Match, соответствующим совпадающей части
>>> m_iter = re.finditer (r'ab + c ',' abc ac adc abbbc ')
>>> для m в m_iter:
... печать (м)
...
& Объект LTre.Match; span = (0, 3), match = 'abc'>
& Объект LTre.Match; промежуток = (11, 16), совпадение = 'abbbc'>
При необходимости используйте методы и атрибуты объекта re.Match
. Вы можете скопировать re.findall
также.
>>> m_iter = re.finditer (r'ab + c ',' abc ac adc abbbc ')
>>> для m в m_iter:
... print (m [0] .upper (), m.span (), sep = '\ t')
...
ABC (0, 3)
ABBBC (11, 16)
# то же, что: re.findall (r '(. *?) / (. *?) / (. *?),', d)
>>> d = '2020/04 / 25,1986 / Mar / 02,77 / 12/31'
>>> m_iter = re.finditer (r '(. *?) / (. *?) / (. *?),', d)
>>> [m.groups () для m в m_iter]
[('2020', '04', '25'), ('1986', 'март', '02')]
С выхода
рэ.finditer
— это объект-итератор, вы не можете перебирать его снова без переназначения. Не в случае сre.findall
, который дает список.
>>> d = '2020/04 / 25,1986 / Mar / 02,77 / 12/31'
>>> m_iter = re.finditer (r '(. *?),', d)
>>> [m [1] вместо m в m_iter]
['2020/04/25', '1986/2 марта']
>>> [m [1] вместо m в m_iter]
[]
Группы захвата также влияют на функцию re.split
. Если шаблон, используемый для разделения, содержит группы захвата, части, соответствующие этим группам, также будут частью выходного списка.
# без группы захвата
>>> re.split (r'1 * 4? 2 ',' 31111111111251111426 ')
['3', '5', '6']
# для включения совпадающих частей шаблона в вывод
>>> re.split (r '(1 * 4? 2)', '31111111111251111426')
['3', '11111111112', '5', '111142', '6']
Если часть шаблона находится за пределами группы захвата, сопоставленный таким образом текст не будет на выходе. Если группа захвата не участвовала, в выходном списке она будет представлена как Нет
.
# здесь 4? 2 вне группы захвата, поэтому эта часть не будет выводиться
>>> re.split (r '(1 *) 4? 2', '31111111111251111426')
['3', '1111111111', '5', '1111', '6']
# пример нескольких групп захвата
# обратите внимание, что часть, соответствующая b +, отсутствует в выводе
>>> re.split (r '(a +) b + (c +)', '3.14aabccc42')
['3.14', 'aa', 'ccc', '42']
# здесь (4)? ноль совпадений в первый раз
>>> re.split (r '(1 *) (4)? 2', '31111111111251111426')
['3', '1111111111', Нет, '5', '1111', '4', '6']
Использование групп захвата и maxsplit = 1
дает поведение, подобное str.перегородка
методом.
# first element - часть до первого совпадения
# второй элемент - это часть, совпадающая с самим шаблоном
# третий элемент - это оставшаяся часть входной строки
>>> re.split (r '(a + b + c +)', '3.14aabccc42abc88', maxsplit = 1)
['3.14', 'aabccc', '42abc88']
re.subn
имеет те же функциональные возможности, что и re.sub
, за исключением того, что вывод является кортежем. Первый элемент кортежа — это тот же результат, что и функция re.sub
.Второй элемент показывает количество сделанных замен. Другими словами, вы также получаете количество совпадений.
re.subn (шаблон, repl, string, count = 0, flags = 0)
>>> Приветствие = 'Хороших выходных'
>>> re.sub (r'e ',' E ', приветствие)
'Хороших выходных'
# с re.subn можно сделать вывод, что было сделано 5 замен
>>> re.subn (r'e ',' E ', приветствие)
('Хорошие выходные', 5)
Вот пример, который выполняет условную операцию в зависимости от того, была ли замена успешной.
>>> word = 'coffining'
# рекурсивно удалить 'fin'
>>> в то время как True:
... слово, cnt = re.subn (r'fin ',' ', word)
... если cnt == 0:
... перерыв
...
>>> слово
'винтик'
Примечание | Описание |
---|---|
re.Match object | получить подробную информацию, такую как сопоставленные части, местоположение и т. Д. |
m [0] or m.group (0 ) | вся согласованная часть рэ.Соответствие объекта м |
м [1] или м. Группа (1) | согласованная часть первой группы захвата |
м [2] или м. Группа (2 ) | согласованная часть второй группы захвата и так далее |
m.groups () | кортеж согласованных частей всех групп захвата |
m.span () | start и end + 1 индекс всей согласованной части |
передать число, чтобы получить диапазон этой конкретной группы захвата | |
также может использовать м.start () и m.end () | |
re.sub (r'pat ', f, s) | function f получит re.Match объект в качестве аргумента |
с использованием dict | строка замены на основе сопоставленного текста в качестве ключа словаря |
ex: re.sub (r'pat ', lambda m: d.get (m [0], default), s ) | |
re.findall | возвращает все совпадения в виде списка строк |
re.findall (pattern, string, flags = 0) | |
если используется 1 группа захвата, возвращаются только ее совпадения | |
1+, каждый элемент будет кортежем групп захвата | |
часть соответствует шаблону вне группы не будет на выходе | |
пустые совпадения будут представлены пустой строкой | |
re.finditer | итератор с re.Match объект для каждого совпадения |
ре.finditer (pattern, string, flags = 0) | |
re.split | группы захвата влияют на re.split тоже |
текст, сопоставленный группами, будет частью вывода | |
часть, соответствующая шаблону вне группы, не будет на выходе | |
группа, которая не соответствует, будет представлена Нет | |
re.subn | дает кортеж измененной строки и номера замен |
рэ.subn (шаблон, repl, string, count = 0, flags = 0) |
В этой главе представлены различные способы работы с различными совпадающими частями входной строки. re.Match
объект помогает вам получить часть, совпадающую с шаблоном RE и группами захвата, местоположением совпадения и т. Д. Функции могут использоваться в разделе замены, который получает объект re.Match
в качестве аргумента. Используя функции, вы можете выполнять замены на основе сопоставлений dict
. Чтобы получить все совпадения вместо первого совпадения, вы можете использовать re.findall
(который дает список строк в качестве вывода) и re.finditer
(который дает итератор объектов re.Match
). Вы также узнали, как группы захвата влияют на вывод функций re.findall
и re.split
. В следующих главах вы увидите еще много примеров использования группировок. Функция re.subn
аналогична функции re.sub
, но дополнительно также дает количество совпадений.
a) Для данных строк извлечь совпадающую часть от первого -
до последнего t
.
>>> str1 = 'Это самый большой фрукт, который ты видел?'
>>> str2 = 'Ваша миссия - последовательно читать и практиковаться'
>>> pat = re.compile () ##### добавьте свое решение сюда
##### добавьте сюда свое решение для str1
'самый большой плод'
##### добавьте сюда свое решение для str2
"ission - это читать и последовательно практиковать"
b) Найдите начальный индекс первого появления - это
или ,
или были
или от до
для заданных входных строк.
>>> s1 = 'соответствие после последнего символа новой строки'
>>> s2 = 'а затем вы хотите протестировать'
>>> s3 = 'тогда до свидания'
>>> s4 = 'кого было там видеть?'
>>> pat = re.compile () ##### добавьте свое решение сюда
##### добавьте сюда свое решение для s1
12
##### добавьте сюда свое решение для s2
4
##### добавьте сюда свое решение для s3
2
##### добавьте сюда свое решение для s4
4
c) Найдите начальный индекс последнего появления - это
или ,
или было
или от до
для заданных входных строк.
>>> s1 = 'соответствие после последнего символа новой строки'
>>> s2 = 'а затем вы хотите протестировать'
>>> s3 = 'тогда до свидания'
>>> s4 = 'кого было там видеть?'
>>> pat = re.compile () ##### добавьте свое решение сюда
##### добавьте сюда свое решение для s1
12
##### добавьте сюда свое решение для s2
18
##### добавьте сюда свое решение для s3
17
##### добавьте сюда свое решение для s4
14
d) Данная входная строка содержит :
ровно один раз.Извлеките все символы после :
в качестве вывода.
>>> ip = 'фрукты: яблоко, манго, гуава, черника'
##### добавьте свое решение здесь
'яблоко, манго, гуава, черника'
e) Данные входные строки содержат текст, за которым следует -
, за которым следует число. Замените это число его значением log
, используя math.log ()
.
>>> s1 = 'первый-3.14'
>>> s2 = 'следующий-123'
>>> pat = re.compile () ##### добавьте сюда свое решение
>>> импорт математики
>>> pat.sub () ##### добавьте сюда свое решение для s1
"первый-1.1442227992"
>>> pat.sub () ##### добавьте сюда свое решение для s2
'следующий-4.812184355372417'
f) Заменить все вхождения par
на spar
, Spar
на extra
и park
на garden
для заданных входных строк.
>>> str1 = 'квартира имеет парк'
>>> str2 = 'у тебя есть запасной кабель?'
>>> str3 = 'написать парсер'
##### добавьте свое решение здесь
>>> погладить.sub () ##### добавьте здесь свое решение для str1
'квартира имеет сад'
>>> pat.sub () ##### добавьте сюда свое решение для str2
"у вас есть лишний кабель"
>>> pat.sub () ##### добавьте сюда свое решение для str3
'пиши реже'
g) Извлечь все слова между (
и )
из заданной входной строки в виде списка. Предположим, что входные данные не будут содержать разорванных скобок.
>>> ip = 'другой (способ) повторного использования (части) сопоставленных (по) группам захвата'
>>> ре.findall () ##### добавьте свое решение здесь
['путь', 'часть', 'по']
h) Извлечь все вхождения i) Используйте j) Это продолжение предыдущего вопроса. k) Используйте l) Для данного списка строк измените элементы на кортеж исходного элемента, и количество раз м) В данной входной строке есть поля, разделенные Обратите внимание, что это отличается от n) Преобразуйте строки, разделенные запятыми, в соответствующие объекты Регулярное выражение в Python используется для сопоставления шаблона со строкой. Формально регулярное выражение - это последовательность символов, определяющих шаблон поиска. Регулярные выражения Python - мощный способ сопоставления текстовых шаблонов.Модуль Давайте рассмотрим несколько распространенных примеров модуля Python re. Это встроенный модуль Python, поэтому нам не нужно его устанавливать. Давайте посмотрим на примере той же Выход Как вы можете видеть, выходные данные показывают, что действительно существует соответствие для шаблона. Мы искали простое слово Чтобы получить список всех совпавших строк, мы используем Прежде чем идти дальше, мы рассмотрим определенные правила, которым следуют регулярные выражения, которые необходимы для создания шаблонных строк. Это идентификаторы шаблонов и правило, которому следует каждый идентификатор. Вот пример использования некоторых из приведенных выше правил. Приведенный ниже шаблон соответствует одному или нескольким Выход No related posts. до следующего появления
>
, при условии, что есть хотя бы один символ между и
>
.
>>> ip = 'a & LTapple> 1 b & LTbye> 2 c & LTcat>'
>>> re.findall () ##### добавьте свое решение сюда
['& LTapple>', 'b & LTbye>', 'c & LTcat>']
re.findall
, чтобы получить вывод, как показано ниже для заданных входных строк. Внимательно обратите внимание на символы, используемые во входных строках.
>>> row1 = '-2,5 4, + 3 + 42, -53 4356246, -357532354'
>>> row2 = '1.32, -3.14 634,5.63 63.3e3,9
43.235'
>>> pat = re.compile () ##### добавьте свое решение сюда
>>> pat.findall (row1)
[('-2', '5'), ('4', '+3'), ('+42', '-53'), ('4356246', '-357532354')]
>>> pat.findall (row2)
[('1.32', '-3.14'), ('634', '5.63 '), ('63 .3e3', '9
43.235')]
row1
найдите сумму целых чисел каждого элемента кортежа. Например, сумма -2
и 5
равна 3
. row2
найдите сумму чисел с плавающей запятой каждого элемента кортежа. Например, сумма 1,32
и -3,14
будет -1,82
.
>>> row1 = '-2,5 4, + 3 + 42, -53 4356246, -357532354'
>>> row2 = '1.32, -3,14 634,5,63 63,3e3,9
43,235 '
# должен быть таким же, как в предыдущем вопросе
>>> pat = re.compile () ##### добавьте свое решение сюда
##### добавьте сюда свое решение для row1
[3, 7, -11, -353176108]
##### добавьте сюда свое решение для row2
[-1,82, 639,63, 9
43,234]
re.split
, чтобы получить результат, как показано ниже.
>>> ip = '42: no-output; 1000: car-truck; SQEX49801 '
>>> re.split () ##### добавьте свое решение сюда
['42', 'вывод', '1000', 'грузовик', 'SQEX49801']
t
встречается в этом элементе.
>>> words = ['sequoia', 'attest', 'tattletale', 'asset']
##### добавьте свое решение здесь
[('sequoia', 0), ('attest', 3), ('tattletale', 4), ('asset', 1)]
:
. Каждое поле содержит четыре прописных алфавита, за которыми могут следовать две цифры. Игнорируйте последнее пустое поле. См. Docs.python: Match.groups и используйте re.finditer
, чтобы получить результат, как показано ниже. Если дополнительных цифр нет, покажите «NA»
вместо None
.
>>> ip = 'TWXA42: JWPA: NTED01:'
##### добавьте свое решение здесь
[('TWXA', '42'), ('JWPA', 'NA'), ('NTED', '01')]
re.findall
, который просто выдаст пустую строку вместо None
, когда группа захвата не участвует. dict
, как показано ниже.
>>> row1 = 'name: rohan, maths: 75, phy: 89,'
>>> row2 = 'имя: роза, математика: 88, физ: 92,'
>>> pat = re.compile () ##### добавьте сюда свое решение
##### добавьте сюда свое решение для row1
{'name': 'rohan', 'maths': '75', 'phy': '89'}
##### добавьте сюда свое решение для row2
{'name': 'rose', 'maths': '88', 'phy': '92'}
Регулярное выражение в Python - AskPython
re
, сокращение от регулярного выражения, представляет собой модуль Python, который предоставляет нам все возможности регулярных выражений. 1. Использование модуля Python re
1.1) re.search ()
re.search (pattern, str)
используется для поиска последовательности pattern
, которая является регулярным выражением, в пределах str
(строка поиска) и возвращает совпадение, если образец найден.
импорт ре
str = 'Это образец текста, который мы используем для поиска шаблона в тексте.'
pat = r'text '
match = re.search (pat, str)
если совпадение отсутствует:
print ('Шаблон не найден')
еще:
print ('Образец найден!')
print ('Сопоставить объект', сопоставить)
Выкройка найдена!
Соответствующий объект
text
в str
, а диапазон обозначает индексы совпадения.Таким образом, совпадают str [17]
- str [20]
, что соответствует подстроке текста
, как и ожидалось. Но это дает только первое совпадение. 1.2) re.findall ()
re.findall (pat, str)
, чтобы вернуть список всех совпавших строк (который может быть пустым).
>>> match = re.findall (pat, str)
>>> print (совпадения)
['текст', 'текст']
re.findall ()
- чрезвычайно мощная функция для извлечения шаблонов, и ее можно использовать для чего угодно, например для поиска в файлах.
импорт ре
с open ('text.txt', 'r') как f:
совпадения = re.findall (r'pattern ', f.read ())
печать (совпадения)
2. Правила регулярных выражений в Python
2.1) Идентификаторы
Образец Правило \ d Соответствует любому числу \ D Соответствует чему угодно, кроме чисел \ s Соответствует одному пробелу \ S Соответствует чему угодно, кроме пробела \ w Соответствует любой букве \ W Соответствует чему угодно, кроме буквы . Выполнить сопоставление в начале строки {1,3} Сопоставить, если количество повторений может быть от 1 до 3 раз {3} Соответствует, если количество повторений равно 3 разу {3,} Соответствует 3 или более раз ] Соответствует любому одиночному символу от a до z - это
слов, за которыми следует пробел, после которого должно быть одно или несколько совпадений любого буквенно-цифрового символа, запятой или пробела. Матч ниже останавливается на ближайшей точке, так как не входит в группу.
импорт ре
str = 'В колледже обучается от 10 000 до 20 000 студентов. Это может означать что угодно. \ N '
pat = r'are {1,} \ s [a-z0-9, \ s] + '
match = re.search (pat, str)
совпадения = re.findall (pat, str)
если совпадение отсутствует:
print ('Шаблон не найден')
еще:
print ('Образец найден!')
print ('Сопоставить объект', сопоставить)
print ('Список всех совпадений:', совпадений)
Выкройка найдена!
Соответствующий объект