Рассмотрим регулярные выражения в Python, начиная синтаксисом и заканчивая примерами использования.
Примечание Не стоит забывать, что регулярные выражения не всегда оптимальны, и для простых операций часто достаточно встроенных в Python функций.
Хотите узнать больше? Обратите внимание на статью о регулярках для новичков.
import re
А вот наиболее популярные методы, которые предоставляет модуль:
import re
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
<_sre.SRE_Match object at 0x0000000009BE4370>
Искомая подстрока найдена. Чтобы вывести её содержимое, применим метод group() (мы используем «r» перед строкой шаблона, чтобы показать, что это «сырая» строка в Python):
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
AV
Теперь попробуем найти «Analytics» в данной строке. Поскольку строка начинается на «AV», метод вернет None:
result = re.match(r'Analytics', 'AV Analytics Vidhya AV')
print result
Результат:
None
Также есть методы start() и end() для того, чтобы узнать начальную и конечную позицию найденной строки.
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.start()
print result.end()
Результат:
0
2
Эти методы иногда очень полезны для работы со строками.
result = re.search(r'Analytics', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
Analytics
Метод search() ищет по всей строке, но возвращает только первое найденное совпадение.
result = re.findall(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
['AV', 'AV']
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, и в результате строка была разделена на две части вместо трех.
result = re.sub(r'India', 'the World', 'AV is largest Analytics community of India')
print result
Результат:
'AV is largest Analytics community of the World'
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.
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.findall(r'^\w+', 'AV is largest Analytics community of India')
print result
Результат:
['AV']
Если мы используем $ вместо ^, то мы получим последнее слово, а не первое:
result = re.findall(r'\w+$', 'AV is largest Analytics community of India')
print result
Результат:
[‘India’]
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']
result = re.findall(r'@\w+', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print result
Результат:
['@gmail', '@test', '@analyticsvidhya', '@rest']
Как видим, части «.com», «.in» и т. д. не попали в результат. Изменим наш код:
result = re.findall(r'@\w+.\w+', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print result
Результат:
['@gmail.com', '@test.in', '@analyticsvidhya.com', '@rest.biz']
Второй вариант — вытащить только домен верхнего уровня, используя группировку — ( ):
result = re.findall(r'@\w+.(\w+)', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print result
Результат:
['com', 'in', 'com', 'biz']
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.findall(r'\b[^aeiouAEIOU]\w+', 'AV is largest Analytics community of India')
print result
Результат:
[' is', ' largest', ' Analytics', ' community', ' of', ' India']
В результат попали слова, «начинающиеся» с пробела. Уберем их, включив пробел в диапазон в квадратных скобках:
result = re.findall(r'\b[^aeiouAEIOU ]\w+', 'AV is largest Analytics community of India')
print result
Результат:
['largest', 'community']
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
https://tproger.ru/jobs/course-teacher-informatics/?utm_source=in_text
Пример содержимого 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')]
Источник статьи: https://tproger.ru/translations/regular-expression-python/#part2
Для чего нужны регулярные выражения?
- для определения нужного формата, например телефонного номера или email-адреса;
- для разбивки строк на подстроки;
- для поиска, замены и извлечения символов;
- для быстрого выполнения нетривиальных операций.
Примечание Не стоит забывать, что регулярные выражения не всегда оптимальны, и для простых операций часто достаточно встроенных в Python функций.
Хотите узнать больше? Обратите внимание на статью о регулярках для новичков.
Регулярные выражения в Python
В Python для работы с регулярками есть модуль re. Его нужно просто импортировать:import re
А вот наиболее популярные методы, которые предоставляет модуль:
- re.match()
- re.search()
- re.findall()
- re.split()
- re.sub()
- re.compile()
re.match(pattern, string)
Этот метод ищет по заданному шаблону в начале строки. Например, если мы вызовем метод match() на строке «AV Analytics AV» с шаблоном «AV», то он завершится успешно. Но если мы будем искать «Analytics», то результат будет отрицательный:import re
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
<_sre.SRE_Match object at 0x0000000009BE4370>
Искомая подстрока найдена. Чтобы вывести её содержимое, применим метод group() (мы используем «r» перед строкой шаблона, чтобы показать, что это «сырая» строка в Python):
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
AV
Теперь попробуем найти «Analytics» в данной строке. Поскольку строка начинается на «AV», метод вернет None:
result = re.match(r'Analytics', 'AV Analytics Vidhya AV')
print result
Результат:
None
Также есть методы start() и end() для того, чтобы узнать начальную и конечную позицию найденной строки.
result = re.match(r'AV', 'AV Analytics Vidhya AV')
print result.start()
print result.end()
Результат:
0
2
Эти методы иногда очень полезны для работы со строками.
re.search(pattern, string)
Метод похож на match(), но ищет не только в начале строки. В отличие от предыдущего, search() вернёт объект, если мы попытаемся найти «Analytics»:result = re.search(r'Analytics', 'AV Analytics Vidhya AV')
print result.group(0)
Результат:
Analytics
Метод search() ищет по всей строке, но возвращает только первое найденное совпадение.
re.findall(pattern, string)
Возвращает список всех найденных совпадений. У метода findall() нет ограничений на поиск в начале или конце строки. Если мы будем искать «AV» в нашей строке, он вернет все вхождения «AV». Для поиска рекомендуется использовать именно findall(), так как он может работать и как re.search(), и как re.match().result = re.findall(r'AV', 'AV Analytics Vidhya AV')
print result
Результат:
['AV', 'AV']
re.split(pattern, string, [maxsplit=0])
Этот метод разделяет строку по заданному шаблону.result = re.split(r'y', 'Analytics')
print result
Результат:
['Anal', 'tics']
В примере мы разделили слово «Analytics» по букве «y». Метод split() принимает также аргумент maxsplit со значением по умолчанию, равным 0. В данном случае он разделит строку столько раз, сколько возможно, но если указать этот аргумент, то разделение будет произведено не более указанного количества раз. Давайте посмотрим на примеры:
result = re.split(r'i', 'Analytics Vidhya')
print result
Результат:
['Analyt', 'cs V', 'dhya'] # все возможные участки.
result = re.split(r'i', 'Analytics Vidhya',maxsplit=1)
print result
Результат:
['Analyt', 'cs Vidhya']
Мы установили параметр maxsplit равным 1, и в результате строка была разделена на две части вместо трех.
re.sub(pattern, repl, string)
Ищет шаблон в строке и заменяет его на указанную подстроку. Если шаблон не найден, строка остается неизменной.result = re.sub(r'India', 'the World', 'AV is largest Analytics community of India')
print result
Результат:
'AV is largest Analytics community of the World'
re.compile(pattern, repl, string)
Мы можем собрать регулярное выражение в отдельный объект, который может быть использован для поиска. Это также избавляет от переписывания одного и того же выражения.pattern = re.compile('AV')
result = pattern.findall('AV Analytics Vidhya AV')
print result
result2 = pattern.findall('AV is largest analytics community of India')
print result2
Результат:
['AV', 'AV']
['AV']
До сих пор мы рассматривали поиск определенной последовательности символов. Но что, если у нас нет определенного шаблона, и нам надо вернуть набор символов из строки, отвечающий определенным правилам? Такая задача часто стоит при извлечении информации из строк. Это можно сделать, написав выражение с использованием специальных символов. Вот наиболее часто используемые из них:
Оператор | Описание |
---|---|
. | Один любой символ, кроме новой строки \n. |
? | 0 или 1 вхождение шаблона слева |
+ | 1 и более вхождений шаблона слева |
* | 0 и более вхождений шаблона слева |
\w | Любая цифра или буква (\W — все, кроме буквы или цифры) |
\d | Любая цифра [0-9] (\D — все, кроме цифры) |
\s | Любой пробельный символ (\S — любой непробельный символ) |
\b | Граница слова |
[..] | Один из символов в скобках ([^..] — любой символ, кроме тех, что в скобках) |
\ | Экранирование специальных символов (\. означает точку или \+ — знак «плюс») |
^ и $ | Начало и конец строки соответственно |
{n,m} | От n до m вхождений ({,m} — от 0 до m) |
a|b | Соответствует a или b |
() | Группирует выражение и возвращает найденный текст |
\t, \n, \r | Символ табуляции, новой строки и возврата каретки соответственно |
Ну хватит теории. Рассмотрим примеры использования регулярок в Python.
Задачи
Вернуть первое слово из строки
Сначала попробуем вытащить каждый символ (используя .)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.findall(r'^\w+', 'AV is largest Analytics community of India')
print result
Результат:
['AV']
Если мы используем $ вместо ^, то мы получим последнее слово, а не первое:
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+', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print result
Результат:
['@gmail', '@test', '@analyticsvidhya', '@rest']
Как видим, части «.com», «.in» и т. д. не попали в результат. Изменим наш код:
result = re.findall(r'@\w+.\w+', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print result
Результат:
['@gmail.com', '@test.in', '@analyticsvidhya.com', '@rest.biz']
Второй вариант — вытащить только домен верхнего уровня, используя группировку — ( ):
result = re.findall(r'@\w+.(\w+)', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
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.findall(r'\b[^aeiouAEIOU]\w+', 'AV is largest Analytics community of India')
print result
Результат:
[' is', ' largest', ' Analytics', ' community', ' of', ' India']
В результат попали слова, «начинающиеся» с пробела. Уберем их, включив пробел в диапазон в квадратных скобках:
result = re.findall(r'\b[^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-код содержится в строке.https://tproger.ru/jobs/course-teacher-informatics/?utm_source=in_text
Пример содержимого 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')]
Источник статьи: https://tproger.ru/translations/regular-expression-python/#part2