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

В языке Python регулярные выражения представляются стандартной библиотекой.

Когда мы пишем регулярное выражение мы хотим чтобы обратный слэш вел себя как обратный слэш.
x = "hello\nworld"
print(x)

x = r"hello\nworld"  # сырая (raw) строка
print(x)

Для описания шаблонов регулярных выражений используются именно сырые строки.

Основные функции

В модуле re находятся четыре основные функции для работы с регулярными выражениями:
print(re.match)  # проверят подходит ли данная строка под данный шаблон
print(re.search)  # находит первую подстроку, которая подходит под данный шаблон
print(re.findall)  # находит все подстроки, которые подходят под данный шаблон
print(re.sub)  # заменить все вхождения подстрок, которые подходят под наш шаблон, чем-нибудь другим

Строка "abc" подходит под шаблон "abc".

Функция match берет строку и бежит с самого начала нашей строки до тех пор пока какой-нибудь префикс нашей строки не подойдет под данное регулярное выражение:
pattern = r"abc"
string = "abcd"
match_object = re.match(pattern, string)
print(match_object)

Однако, если мы хотим найти вхождение нашего шаблона в строку, то мы можем использовать функцию search:
pattern = r"abc"
string = "babc"
match_object = re.search(pattern, string)
print(match_object)

Те числа, которые возвращаются нам внутри span-a, это те же числа, которые мы бы использовали при слайсинге:


Функции findall и sub позволяют найти все вхождения шаблона внутри текста и заменить эти подстроки на что-то другое:
string = "abc, a.c, aac, a-c, aBc, azc"
all_inclusions = re.findall(pattern, string)
print(all_inclusions)

fixed_typos = re.sub(pattern, "abc", string)
print(fixed_typos)

Метасимволы

Метасимволы . ^ $ * + ? { } [ ] \ | ( ) позволяют расширять то множество строк, которые подходят под наш шаблон.

pattern = r"a[abc]c"  # [] -- можно указать множество подходящих символов
string = "abc"  # строки "aac", "abc", "acc" будут подходить под шаблон
match_object = re.match(pattern, string)
print(match_object)

Если мы хотим просто найти символ вопросительного знака, то должны экранировать его с помощью обратного слэша:
import re

pattern = r" english\?"
string = "Do you speak english?"
match = re.search(pattern, string)
print(match)

Можно указать диапазон подходящих символов:
pattern = r"a[a-zA-Z]c"
string = "aBc"
match_object = re.search(pattern, string)
print(match_object)

Символ циркумфлекс ^ используется для описания множества неподходящих символов:
pattern = r"a[^a-zA-Z]c"
string = "a.c"
match_object = re.search(pattern, string)
print(match_object)

Для некоторых групп символов существует короткая запись:
  • \d ~ [0-9] -- цифры
  • \D ~ [^0-9]
  • \s ~ [ \t\n\r\f\v] -- пробел, табуляция, перенос строки, перенос каретки, перенос страницы, вертикальная табуляция
  • \S ~ [^ \t\n\r\f\v]
  • \w ~ [a-zA-Z0-9_] -- буквы + цифры + _
  • \W ~ [^a-zA-Z0-9_]
Их можно совмещать:
pattern = r"a[\w.]c"
string = "a.c"
match_object = re.search(pattern, string)
print(match_object)

Любой символ кроме переноса строки подходит под метасимвол точки.

Метасимволы повтора

Также можно указывать, что нас интересует некоторое число повторов символа или группы символов:
pattern = r"ab*a"  # любое число символов b, включая 0
string = "aa, aba, abba"
all_inclusions = re.findall(pattern, string)
print(all_inclusions)

Если нас интересует только положительное число (> 0) включений, то используется символ +:
pattern = r"ab+a"
string = "aa, aba, abba"
all_inclusions = re.findall(pattern, string)
print(all_inclusions)

Используя метасимвол ? можно указать, что нас интересует 0 или 1 вхождение символа b:
pattern = r"ab?a"
string = "aa, aba, abba"
all_inclusions = re.findall(pattern, string)
print(all_inclusions)

А вот если нас интересует конкретно число вхождений или от какого-то до какого-то количества, то можно использовать метасимвол фигурных скобок:
pattern = r"ab{2,4}a"
string = "aa, aba, abba, abbba, abbbba"
all_inclusions = re.findall(pattern, string)
print(all_inclusions)

Метасимволы повтора * и + являются жадными, т.е. они пытаются вовлечь в себя как можно больше символов при том чтобы наше регулярное выражение удовлетворилось целиком. При жадном подходе мы сначала пытаемся выбрать строку максимальной длины, которая нас удовлетворяет, а затем проверить, а вот то, что осталось от нашей строки, оно подходит под остаток шаблона, который у нас остался, если нет, то мы выкидываем один символ с конца и снова проверяем.
pattern = r"a[ab]+a"
string = "abaaba"
print(re.match(pattern, string))
print(re.findall(pattern, string))

Можно пойти не жадным способом, т.е. найти наименьшее число вхождений, которое бы удовлетворило наше регулярное выражение. Для этого мы можем использовать ? после нашего метасимвола.
pattern = r"a[ab]+?a"
string = "abaaba"
print(re.match(pattern, string))
print(re.findall(pattern, string))

Группировка символов

Это нужно для того чтобы мы могли использовать метасимволы повтора для какой-нибудь группы символов, а не для одиночного символа. Для группировки используются круглые скобки:
pattern = r"(test)*"
string = "testtest"
print(re.match(pattern, string))
Через метасимвол или | можно указать, что нам подходит одна из групп символов:
pattern = r"(test|text)*"
string = "testtext"
print(re.match(pattern, string))
Метасимвол | обладает наименьшим приоритетом в регулярных выражениях.

Посредством групп мы запоминаем какие символу попал в конкретную группу:
pattern = r"((abc)|(test|text)*)"
string = "abc"
match = re.match(pattern, string)
print(match)
print(match.groups())

Для того чтобы достать значение группы используется метод group:
pattern = r"Hello (abc|test)"
string = "Hello abc"
match = re.match(pattern, string)
print(match)
print(match.group(0))
print(match.group(1))

Можно использовать найденную группу прямо внутри регулярного выражения:
import re

pattern = r"(\w+)-\1"
string = "test-test"
match = re.match(pattern, string)
print(match)

Мы можем переиспользовать эту группу внутри функции sub:
import re

pattern = r"(\w+)-\1"
string = "test-test chow-chow"
duplicates = re.sub(pattern, r"\1", string)
print(duplicates)

При использовании групп функция findall возвращает кортеж групп.
import re

pattern = r"((\w+)-\2)"
string = "test-test chow-chow"
duplicates = re.findall(pattern, string)
print(duplicates)

Флаги

Можно указать, что нас не интересует являются ли буквы заглавными или строчными.
import re

x = re.match(r"(te)*?xt", "TEXT", re.IGNORECASE | re.DEBUG)
print(x)


Комментариев нет:

Отправить комментарий