Полный экскурс по регулярным выражениям в Python
Регулярные выражения можно использовать для поиска, редактирования текста и манипулирования им. Это открывает широкий спектр возможностей во всех направлениях разработки на Python. Регулярные выражения широко используются почти всеми стартапами и имеют хорошую популярность в разработке приложений, а также делают регулярные выражения незаменимыми для современного программиста.
В этой статье мы рассмотрим следующие концепции:
- Почему мы используем регулярные выражения?
- Что такое регулярные выражения?
- Основные операции с регулярными выражениями
- Проверка email с помощью регулярных выражений
- Проверка номера телефона с помощью регулярных выражений
Зачем использовать регулярные выражения?
Чтобы ответить на этот вопрос, мы рассмотрим различные проблемы, с которыми мы сталкиваемся, которые, в свою очередь, решаются с помощью регулярных выражений.
Рассмотрим следующий сценарий:
У вас есть файл журнала событий, содержащий большое количество данных. И из этого файла журнала вы хотите получить только дату и время. Как вы можете видеть в следующем фрагменте, на первый взгляд, читаемость файла достаточно низкая.
[2024-06-07 06:53:41 +0500][7529][PROD]GET/robots.txt[2024-06-
07 06:53:42 +0500] [7529] [PROD] GET /library/articles/10[2024-
06-07 06:56:16 +0500][7019][PROD]GET / [2024-06-07 07:00:02
+0500][7018][PROD]GET/app/.git/config
[2024-06-07 07:06:04 +0500][7018][PROD]GET /[2024-06-07
07:07:51 +0500][7530][PROD] GET /[2024-06-07 07:12:12 +0500]
[7531] [PROD] GET /robots.txt[2024-06-07 07:15:16 +0500]
[7531] [PROD] GET /currency/XDR[2024-06-07 07:29:10 +0500][7529
][PROD] GET /[2024-06-07 07:39:03 +0500] [7530][PROD]GET/li
brary/articles/26[2024-06-07 07:39:04 +0500][7530][PROD]GE
T/img/get[2024-06-07 08:12:17 +0500][7531][PROD]GET/robots.t
xt[2024-06-07 08:15:05 +0500] [7529][PROD]GET/search/[2024-06-
07 08:15:09 +0500] [7529] [PROD] GET /apps/creativebutton
[2024-06-07 08:15:15 +0500][7529][PROD]GET /currency/CNY[2024-06
-07 08:15:20 +0500] [7529] [PROD] GET /currency/JPY
В этом случае можно использовать регулярные выражения, чтобы легко распознавать шаблоны и извлекать необходимую информацию.
Рассмотрим следующий сценарий: вы продавец, и у вас много адресов электронной почты, и многие из этих адресов являются нерабочими (неправильными). Посмотрите на изображение ниже:
Что можно сделать, так это использовать регулярные выражения, с помощью которых вы можете проверить формат адресов электронной почты и отфильтровать неправильные.
Следующий сценарий очень похож на тот, что описан в примере с продавцом. Рассмотрим следующее изображение:
Как мы можем проверить номер телефона?
Каждое правильное число будет иметь определенную закономерность, которую можно отследить с помощью регулярных выражений.
Далее следует еще один простой сценарий. База данных студентов.
У нас есть база данных учащихся, содержащая такие данные, как имя, возраст и адрес. Рассмотрим случай, когда код города изначально был 199406, но теперь был изменен на 190000. Вручную обновлять его для каждого учащегося было бы трудоемким и очень длительным процессом.
По сути, чтобы решить эти проблемы с помощью регулярных выражений, мы сначала находим определенную строку из данных учащихся, содержащую код, а затем заменяем их все новыми.
Регулярные выражения можно использовать в большинстве языков:
- Java
- Python
- Ruby
- Swift
- Scala
- Groovy
- C#
- PHP
- Javascript
Существует еще масса сценариев, в которых нам помогают регулярные выражения. Рассмотрим их с вами о них в следующих разделах этой статьи.
Что такое регулярные выражения?
Регулярное выражение используется для определения шаблона поиска в текстовой строке. Это также помогает определить корректность данных, и даже такие операции, как поиск, замена и форматирование данных, возможны с использованием регулярных выражений.
Рассмотрим следующий пример:
Имя | Фамилия | Компания | Адрес | Город | Область | Код | Телефон | Почта |
---|---|---|---|---|---|---|---|---|
Василий | Петров | Рога и Копыта | Савеловская 1, 256 | Санкт-Петербург | Санкт-Петербург | 190002 | +79027652312 | v.petrov92@mail.ru |
Аркадий | Васильев | Мечта | Транспортная 12, 222 | Москва | Москва | 105005 | +79112789009 | a.vasiliev00@mail.ru |
Елена | Ольхова | Сторбс-М | Раскатная 1 | Химки | Московская область | 124489 | +79550981133 | elelel@yandex.ru |
Александра | Корнилова | Амакас | Пр-кт Космонавтов 12, 9 | Екатеринбург | Екатеринбург | 620012 | +79221436756 | uchmuchu@bk.ru |
Валерий | Лерьев | Хлебовоз | Майская 9 | Сызрань | Самарская область | 446008 | +79846578373 | sijka99@list.ru |
Игорь | Степанчук | Ортград | Школьный пер. 2, 31 | Курган | Курган | 640005 | +79674101970 | cepoz-apeka21@bk.ru |
Юлия | Москвина | Копейка | Социалистическая ул. 55, 9 | Ставрополь | Ульяновская область | 355005 | +7933847724 | rozex_ejugu73@inbox.ru |
Олег | Крафт | Алабай | Пионерская ул. 113, 15 | Чита | Тамбовская область | 672020 | +7903724420 | coduk_iresa33@yandex.ru |
Шамиль | Абдулаев | РНЛИК | Луговой пер. 157, 14 | Ижевск | Смоленская область | 426019 | +79044875091 | fekuful_umu98@aol.com |
Евгений | Мартыненко | Минтраль | Минская ул. 14, 10 | Курск | Республика Татарстан | 305002 | +79896197432 | fafuca-yuce71@mail.ru |
*данные в таблице являются случайной генерацией, совпадение с реальными людьми исключено
Предположим, что из всех данных в данной строке нам нужен только город. Это можно преобразовать в словарь, содержащий только название и город в отформатированном виде. Вопрос теперь в том, можем ли мы определить шаблон для угадывания названия и города? Кроме того, мы можем узнать и возраст. С возрастом все просто, не так ли? это просто целое число.
Что мы будем делать с именем? Если вы посмотрите на шаблон, то увидите, что все имена начинаются с заглавной буквы. С помощью регулярных выражений мы можем определить как имя, так и возраст, используя этот метод.
Рассмотрим следующий код:
import re
Nameage = '''
Василисе 22 и Игорю 33
Тамаре 44 и Олегу 21
'''
ages = re.findall(r'\d{1,3}', Nameage)
names = re.findall(r'[А-Я][а-я]*',Nameage)
ageDict = {}
x = 0
for eachname in names:
ageDict[eachname] = ages[x]
x+=1
print(ageDict)
Сейчас нет необходимости беспокоиться о синтаксисе, но поскольку Python обладает потрясающей удобочитаемостью, вы вполне можете догадаться, что происходит с частью кода, содержащей регулярные выражения.
Вывод
{'Василисе': '22', 'Игорю': '33', 'Тамаре': '44', 'Олегу': '21'}
Операции, которые вы можете выполнять с помощью регулярных выражений
Существует множество операций, которые вы можете выполнить, используя регулярные выражения. Здесь я перечислил несколько из них, которые очень важны для того, чтобы помочь вам лучше понять использование регулярных выражений.
Поиск слова в строке
Рассмотрим следующий фрагмент кода:
import re
if re.search('информ', 'нам нужно проинформировать его о самой свежей информации'):
print('Здесь есть сообщить!')
Все, что мы здесь делаем, - это ищем, есть ли в нашей поисковой строке слово "информ". И если оно есть, то мы получаем вывод о том, что оно здесь присутствует.
Мы можем немного улучшить код, написав метод, который будет находить все вхождения строки в тексте.
import re
allinform = re.findall('информ', 'нам нужно проинформировать его о самой свежей информации')
for i in allinform:
print(i)
Здесь, в данном случае, слово "информ" будет найдено дважды. Одно в слове "проинформировать", а другое - в "информации".
И найти слово в регулярном выражении так же просто, как показано выше.
Создание итератора
Генерация итератора - это простой процесс определения начального и конечного индексов строки и представления отчета о них. Рассмотрим следующий пример:
import re
Str = "нам нужно проинформировать его о самой свежей информации"
for i in re.finditer("информ.", Str):
locTuple = i.span()
print(locTuple)
Для каждого найденного совпадения выводятся начальный и конечный индексы. В результате получим следующий результат:
(13, 20)
(46, 53)
Довольно просто, не так ли?
Нахождение слов с помощью шаблонов
Рассмотрим входную строку, в которой вам нужно сопоставить определенные слова со строкой. Рассмотрим следующий пример кода:
import re
Str = "Суб, суп, сук, суд"
allStr = re.findall("су[бпкд]", Str)
for i in allStr:
print(i)
Что общего в этой строке? Вы можете видеть, что буквы "с" и "у" являются общими для всех входных строк. [бпкд] в коде обозначает конечную букву слов, которые нужно найти. Таким образом, любая подстрока, заканчивающаяся на букву б, п, к или д, будет рассматриваться на предмет соответствия. Любая из этих подстрок, перед которой обязательно стоит в начале "су".
Вывод
суп
сук
суд
Обратите внимание, что все они чувствительны к регистру. По этой причине первое слово не попало под шаблон, так как начинается с большой буквы.
Совпадающий ряд из диапазона символов
Мы хотим вывести все слова, начинающиеся с су и заканчивающиеся на букву, которая должна заканчиваться между к и п (ряд из русского алфавита). Проверяя следующий пример, мы должны понять, что в результате мы должны получить "суп" и "сук", верно?
import re
Str = "суб, суп, сук, суд"
allStr = re.findall("су[к-п]", Str)
for i in allStr:
print(i)
Давайте теперь немного изменим приведенную выше программу, чтобы получить совсем другой результат. Ознакомьтесь с приведенным ниже кодом и попытайтесь уловить разницу между приведенным выше и приведенным ниже:
import re
Str = "суб, суп, сук, суд"
allStr = re.findall("[^су][к-п]", Str)
for i in allStr:
print(i)
Здесь мы поменяли шаблон поиска. Такой код выведет пустой результат, а все потому что в начале хоть мы и предполагаем что строка начинается с символов су, однако символ ^ означает самое начало строки. Соответственно единственное что могло бы попасть под фильтр - слово суб, но у него на конце буква б, не входящая в диапазон букв от к до п.
Замена строки
Далее мы можем проверить другую операцию с использованием регулярных выражений, в которой мы заменяем элемент строки на что-то другое. Это очень просто и может быть продемонстрировано следующим фрагментом кода:
import re
Food = "суб суп сук суд"
regex = re.compile("су[п]")
Food = regex.sub("еда", Food)
print(Food)
В приведенном выше примере слово "суп" заменено словом "еда". Конечный результат будет выглядеть следующим образом. В этом случае используется метод замены регулярных выражений, который также имеет множество практических вариантов использования.
Вывод
суб еда сук суд
Проблема обратного слэша
Рассмотрим пример кода, показанный ниже:
import re
randstr = "Здесь \\Popov.Dev"
print(randstr)
Вывод
Здесь \Popov.Dev
Это проблема с обратным слэшем. Одна из этих символов исчез из вывода. Эту конкретную проблему можно устранить с помощью регулярных выражений.
import re
randstr = "Здесь \\Popov.Dev"
print(re.search(r"\\Popov.Dev", randstr))
Вывод будет следующим:
<re.Match object; span=(6, 16), match='\\Popov.Dev'>
Как вы видите, найдено соответствие для двойных обратных слэшей. И таким образом решить проблему с помощью регулярных выражений.
Совпадение с одним символом
С помощью регулярных выражений можно легко подобрать отдельный символ из строки. Ознакомьтесь со следующим фрагментом кода:
import re
randstr = "12345"
print("Найдено: ", len(re.findall("\d{5}", randstr)))
Ожидаемый результат - 5-е число, которое встречается во входной строке.
Вывод
Найдено: 1
Удаление пробелов в новой строке
Мы можем легко удалить пробелы в новой строке, используя регулярные выражения в Python. Рассмотрим другой фрагмент кода, показанный здесь:
import re
randstr = '''
Отчего так
В России
Березы шумят?
'''
print(randstr)
regex = re.compile("\n")
randstr = regex.sub(" ", randstr)
print(randstr)
Вывод
Отчего так
В России
Березы шумят?
Отчего так В России Березы шумят?
Как вы можете видеть из приведенных выше выходных данных, новые строки были заменены пробелами, и выходные данные печатаются в одной строке.
Есть много других возможностей, которые вы могли бы использовать, в зависимости от того, чем вы хотите заменить строку. Они перечислены ниже:
- \b: Возврат на один символ
- \f: Конец страницы
- \r: Возврат каретки
- \t: Табуляция
- \v: Вертикальная табуляция
Рассмотрим другой пример:
import re
randstr = "12345"
print("Найдено: ", len(re.findall("\d", randstr)))
Вывод
Найдено: 5
Как вы можете видеть из приведенного выше вывода, \d соответствует числам, присутствующим в строке. Однако, если мы заменим его на \D, оно будет соответствовать всему, кроме целого числа, что является полной противоположностью \d.
Практические примеры использования регулярных выражений
Мы рассмотрим 3 основных варианта использования, которые широко используются на ежедневной основе. Ниже приведены кейса, которые мы рассмотрим:
- Верификация номера телефона
- Верификация адреса электронной почты
Верификация номера телефона
Задача: необходимость простой проверки телефонных номеров в любом соответствующем сценарии. Имеются следующие данные:
- +7 9022443344
- +79663125322
- 8-9112735634
- 89492459900
- +7 8424332222
- +79445674752
- +79855762432
- +79997643212
Общий формат телефонного номера выглядит следующим образом:
- Начинается с +7 либо с 8
- Код страны отделяется пробелом, символом - или просто пробелом
- Далее следуют 3 цифры оператора или кода города
- Оставшаяся часть состоит из 7 цифр
Для этого нам потребуется следующий шаблон ^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7}$. Он не идеален, но для задачи поиска российских номеров соответствующих базовым правилам он подходит. Для практики, поместим список номеров в переменную phones и пройдемся по ней с помощью регулярных выражений.
import re
phones = """
+7 9022443344
+79663125322
8-9112735634
89492459900
+7 8424332222
+79445674752
+79855762432
+79997643212
"""
regex = re.compile(r"^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7}$")
for item in phones.split('\n'):
if regex.search(item):
print(f"Номер правильный: {regex.search(item).group()}")
Вывод
Номер правильный: +7 9022443344
Номер правильный: +79663125322
Номер правильный: 89112735634
Номер правильный: 89492459900
Номер правильный: +7 8424332222
Номер правильный: +79445674752
Номер правильный: +79855762432
Номер правильный: +79997643212
Валидация адреса электронной почты
Задача: необходимость простой проверки Email адресов в любом соответствующем сценарии. Имеются следующие данные:
- Petya93@mail.ru
- Venija @ com
- Bp .com
- 321 @.com
Вручную вам достаточно одного внимательного взгляда, чтобы отличить действительные почтовые адреса от недействительных. Но как обстоит дело с тем, что наша программа делает это за нас? Это довольно просто, учитывая, что в данном случае используются следующие рекомендации.
Все адреса электронной почты должны содержать:
- От 1 до 20 строчных и/или прописных букв, цифр, точки и нижние подчеркивания в логине
- Символ @
- От 2 до 20 строчных и прописных букв, цифр в адресе домена
- Символ точки
- от 2 до 3 строчных и прописных букв
Для этого нам потребуется следующий шаблон [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,3}. Для практики, поместим список адресов в переменную emails и пройдемся по ней с помощью регулярных выражений.
import re
emails = """
Petya93@mail.ru
Venija @ com
Bp .com
321 @.com
"""
regex = re.compile('[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,3}')
for item in emails.split('\n'):
if regex.search(item):
print(f"Нашел: {regex.search(item).group()}")
Вывод
Нашел: Petya93@mail.ru
Как вы можете убедиться из приведенных выше адресов, у нас есть только один из 4 реальный.
Заключение
Я надеюсь, что это руководство по регулярным выражениям Python поможет вам изучить все основы, необходимые для начала использования регулярных выражений в Python. Это будет вспомогательным материалом, когда вы будете разрабатывать приложения, требующие использования регулярных выражений и аналогичных принципов.
Комментарии
Для того чтобы оставить свое мнение, необходимо зарегистрироваться на сайте