Pithon. Регулярные выражения

Регулярные выражения есть во многих языках: JavaScript, PHP, C#. Даже для 1С есть внешние компоненты, позволяющие работать с регулярными выражениями. Но в Python существует еще и ряд разных фишек для работы с регулярными выражениями, в частности, кроме поиска и сопоставления, в этом языке есть функции, которые, например, позволяют разбить строку по заданному шаблону. Более того, в Python есть функция, которая позволяет компилировать регулярные выражения.

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

  1. Начинается с восьмёрки
  2. Потом идет код города в скобках, от 1 до 5 цифр.
  3. Затем через пробел номер абонента, допускается разделять цифры знаком «-» (тире)

Необходимо проверить корректность ввода. Вот такой код позволит выявить достаточно много ошибок при вводе телефонных номеров:

import re

result = re.match(r'^8 \(\d{1,5}\) \d{1}\d|-$', '8 (3412) 12-34-56')
if result==None:
    print("НЕВЕРНО")
else:
    print ("Корректный номер")

Программа будет «ругаться», если номер телефона начинается не с восьмёрки, пропущены пробелы или скобки, в коде горда слишком много цифр (больше 5) или в скобках вообще нет цифр, если номер телефона начинается не с цифры. То есть, вот так уже нельзя: ‘8 (3412) -12-34-56’.

Правда, программа посчитает корректными и вот такие номера: ‘8 (3412) 12—34-56’, ‘8 (3412) 12-34-56ввв’. Но, для понимания, что такое регулярные выражения, хватит и этого простого примера. Давайте разберём его.

Сначала мы импортируем библиотеку для работы с регулярными выражениями:

import re

В ней есть функция match, которая выполняет сопоставление  строки с шаблоном. Если ни одного сопоставления не найдено, программа возвращает константу None. Теперь о самом шаблоне. Восьмерку мы задаём явно, пробел тоже. А вот скобка является специальным символом, поэтому ее нужно экранировать знаком «\». Знак «\d» обозначает, что тут должна стоять цифра. В фигурных скобках «{1,5}» — задано количество данных, от и до. В нашем случае запись «\d{1,5}» Означает, что должно идти от 1 до 5-ти цифр. Затем опять скобка и пробел: «\) «. После него одна цифра «d{1}». Обратите внимание, что «до» — не задано, значит, задано точно количество символов, не больше не меньше. В данном случае — это одна цифра, чтобы номер не мог начинаться с тире. Ну а потом идет либо цифра, либо тире: «\d|-«. Знак «|» обозначает «или».

А теперь запустим вот такой пример:

import re

result = re.match(r'Мама', 'Мама мыла раму')
if result!=None:
    print(result.group(0))
else:
    print("Не найдено")

Программа напечатает: «Мама».

А если вот так:

import re

result = re.match(r'мыла', 'Мама мыла раму')
if result!=None:
    print(result.group(0))
else:
    print("Не найдено")

То скажет: «не найдено». Функция math может находить шаблоны только в начале строки.

А вот функция serach ищет совпдаения по всей строке:

import re

result = re.search(r'мыла', 'Мама мыла раму')
if result!=None:
    print(result.group(0))
else:
    print("Не найдено")

Функция search хоть и ищет по всей строке, но возвращает только первое найденное совпадение.

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

import re

s="var1 var2 1var var3 2var 123 ThisIsVariable"
result = re.findall(r'[a-zA-Z]{1}[a-zA-Z0-9]+', s)
print(result)

Вот результат ее работы: [‘var1’, ‘var2’, ‘var’, ‘var3’, ‘var’, ‘ThisIsVariable’]. Обратите внимание, что «1var» не является корректным идентификатором, но «var» — является, поэтому именно «var» и попал в список. О таких нюансах следует помнить и быть очень осторожным с регулярными выражениями.

Есть в библиотеке для работы с регулярными выражениями и уже знакомый вам split (см. прошлый урок). Он делает тоже самое, что и split обычной — разбивает строку, согласно разделителям. Только в качестве разделителя тут шаблон регулярного выражения. Например:

import re

s="Это разные слова, словосочетания. Предложения"
result = re.split(r' |\.|\,', s)
print(result)

Программа вернет: «[‘Это’, ‘разные’, ‘слова’, », ‘словосочетания’, », ‘Предложения’]».

Если после запятой или точки буте пропущен пробел, то данная функция также корректно разделит ее. Сравните с функцией split строки:

import re

s="Это разные слова,словосочетания. Предложения"
result = re.split(r' |\.|\,', s)
print(result)
print(s.split())

Результат работы программы:

[‘Это’, ‘разные’, ‘слова’, ‘словосочетания’, », ‘Предложения’]
[‘Это’, ‘разные’, ‘слова,словосочетания.’, ‘Предложения’]

Теперь решим некоторые задачки.

Задача 1. Извлечь даты из строки

Решение.

import re

s='sdfsd 34.3456 12.05.2007, SWERW 56-4532 11.11.2011, ABC 67+8945 12.01.2009'
result = re.findall(r'\d{2}\.\d{2}\.\d{4}', s)
print(result)

Результат работы программы: [‘12.05.2007’, ‘11.11.2011’, ‘12.01.2009’]

Задача 2. Извлечь из строки года, которые в датах.

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

import re

s='sdfsd 34.3456 12.05.2007, SWERW 56-4532 11.11.2011, ABC 67+8945 12.01.2009'
result = re.findall(r'\d{2}\.\d{2}\.(\d{4})', s)
print(result)

Результат: [‘2007’, ‘2011’, ‘2009’].

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

import re

s='sdfsd 34.3456 12.05.2007, SWERW 56-4532 11.11.2011, ABC 67+8945 12.01.2009'
result = re.findall(r'\d{4}', s)
print(result)

То программа вернет много лишнего: [‘3456’, ‘2007’, ‘4532’, ‘2011’, ‘8945’, ‘2009’]

Задача 3. Дана строка, в которой есть адреса электронной почты. Вернуть список доменов.

Решение.

import re

s='abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz'
result = re.findall(r'@(\w+.\w+)', s)
print(result)

Результат: [‘gmail.com’, ‘test.in’, ‘analyticsvidhya.com’, ‘rest.biz’]

Задача 4. Вернуть список слов.

Решение. Хотя мы это делали выше, но есть более красивое решение:

s="Это разные слова,словосочетания. Предложения"
result = re.findall(r'\w+', s)
print(result)

Результат: [‘Это’, ‘разные’, ‘слова’, ‘словосочетания’, ‘Предложения’]

Задача 5. Вернуть список слов русского языка, начинающихся на гласную:

Решение.

s="Это разные слова,словосочетания. Предложения. Какие-то начинаються на гласную, например, яблоко"
result = re.findall(r'\b[аеёиоуыэюяАЕЁИОУЫЭЯ]\w+', s)
print(result)

Результат: [‘Это’, ‘яблоко’]

Comments

So empty here ... leave a comment!

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

Sidebar