Как да използвате модула за регулярни изрази в Python re (съвпадение, търсене, подредба и др.)

Бизнес

За да извършваме обработка на регулярни изрази в Python, използваме модула re от стандартната библиотека. Той ви позволява да извличате, заменяте и разделяте низове, като използвате шаблони за регулярни изрази.

В този раздел първо ще обясним функциите и методите на модула re.

  • Съставяне на шаблони на регулярни изрази:compile()
  • обект на съвпадение
  • Проверете дали началото на символния низ съвпада, извлечете:match()
  • Проверете за съвпадения, които не се ограничават само до началото:search()
  • Проверете дали целият низ съвпада:fullmatch()
  • Получете списък на всички съответстващи части:findall()
  • Получаване на всички съвпадащи части като итератор:finditer()
  • Заменете съответстващата част:sub(),subn()
  • Разделяне на низове с шаблони на регулярни изрази:split()

След това ще обясня метасимволите (специални символи) и специалните последователности на регулярните изрази, които могат да се използват в модула re. В общи линии това е стандартният синтаксис на регулярните изрази, но внимавайте за задаването на флагове (особено за re.ASCII).

  • Метасимволи на регулярни изрази, специални последователности и предупреждения в Python
  • Задаване на флага
    • Ограничено до ASCII символи:re.ASCII
    • Не се различават големи и малки букви:re.IGNORECASE
    • Подберете началото и края на всеки ред:re.MULTILINE
    • Задаване на няколко флага
  • Жадни и нежадни съвпадения

Компилиране на шаблона на регулярния израз: compile()

Има два начина за обработка на регулярни изрази в модула re.

Работете с функция

Първата е функция.re.match(),re.sub()Подобни функции са на разположение за извършване на извличане, заместване и други процеси с помощта на шаблони на регулярни изрази.

Подробностите за функциите ще бъдат описани по-късно, но при всички тях първият аргумент е низът на шаблона на регулярния израз, следван от низ, който трябва да бъде обработен, и т.н. Например в re.sub(), която извършва заместване, вторият аргумент е низът на заместването, а третият аргумент е низът, който трябва да се обработи.

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Обърнете внимание, че [a-z] в шаблона на регулярния израз в този пример означава всеки символ от a до z (т.е. малка азбука), а + означава повторение на предишния шаблон (в този случай [a-z]) един или повече пъти. [a-z]+ съвпада с всеки низ, който повтаря един или повече знаци от малката азбука.

. е метасимвол (символ със специално значение) и трябва да се избягва с обратна наклонена черта.

Тъй като низовете с шаблони на регулярни изрази често използват много обратни наклонени черти, удобно е да се използват необработени низове, както в примера.

Изпълнява се в метод на обект с шаблон на регулярен израз

Вторият начин за обработка на регулярни изрази в модула re е обектният метод за регулярни изрази.

С помощта на re.compile() можете да компилирате низ от шаблони за регулярни изрази, за да създадете обект с шаблони за регулярни изрази.

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()Например същият процес като тези функции може да се изпълни като методи match(),sub() на обекти с регулярни изрази.

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

Всички функции re.xxx(), описани по-долу, се предоставят и като методи на обекта за регулярни изрази.

Ако повтаряте процес, при който се използва един и същ шаблон, по-ефективно е да генерирате обект на регулярен израз с re.compile() и да го използвате наоколо.

В следващия примерен код функцията се използва без компилиране за удобство, но ако искате да използвате един и същ шаблон многократно, се препоръчва да го компилирате предварително и да го изпълните като метод на обект с регулярни изрази.

обект на съвпадение

match(), search() и т.н. връщат обект на съвпадение.

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

Съответстващият низ и позиция се получават чрез следните методи на обекта match.

  • Получаване на местоположението на мача:start(),end(),span()
  • Получаване на съответстващия низ:group()
  • Получаване на символния низ за всяка група:groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

Ако заградите част от шаблона на регулярен израз в низ със скоби(), частта ще бъде обработена като група. В този случай низът на частта, която съответства на всяка група в groups(), може да се получи като кортеж.

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

Проверявайте дали началото на даден низ съвпада, извлечете: match()

match() връща обект match, ако началото на символния низ съвпада с шаблона.

Както беше споменато по-горе, обектът match може да се използва за извличане на съвпадащия подниз или просто за проверка дали е постигнато съвпадение.

match() ще провери само началото. Ако в началото няма съвпадащ низ, връща None.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

Проверка за съвпадения, които не се ограничават само до началото, извличане: search()

Подобно на match() връща обект match, ако има съвпадение.

Ако има няколко съвпадащи части, ще бъде върната само първата съвпадаща част.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Ако искате да получите всички съвпадащи части, използвайте findall() или finditer(), както е описано по-долу.

Проверка за съответствие на целия низ: fullmatch()

За да проверите дали целият низ отговаря на шаблона на регулярния израз, използвайте функцията fullmatch(). Това е полезно, например, за да проверите дали даден низ е валиден като имейл адрес или не.

Ако целият низ съвпада, се връща обект за съвпадение.

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

Ако има несъвпадащи части (само частични съвпадения или никакви съвпадения), се връща None.

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

Функцията fullmatch() беше добавена в Python 3.4. Ако искате да направите същото в по-ранни версии, използвайте match() и съответстващ метасимвол $ в края. Ако целият низ от началото до края не съвпада, се връща None.

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

Получаване на списък с всички съвпадащи части: findall()

функцията findall() връща списък с всички съвпадащи поднизове. Обърнете внимание, че елементите на списъка не са обекти на съвпадение, а низове.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

Броят на съвпадащите части може да се провери с помощта на вградената функция len(), която връща броя на елементите в списъка.

print(len(result))
# 3

Групирането със скоби() в шаблон на регулярен израз връща списък от кортежи, чиито елементи са низовете от всяка група. Това е еквивалентно на groups() в обекта match.

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

Груповите скоби () могат да се вмъкват, така че ако искате да получите и цялото съвпадение, просто затворете цялото съвпадение в скоби ().

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

Ако не бъде намерено съвпадение, се връща празен кортеж.

result = re.findall('[0-9]+', s)
print(result)
# []

Получаване на всички съвпадащи части като итератор: finditer()

finditer() връща всички съвпадащи части като итератор. Елементите не са низове, както при findall(), а обекти на съвпадение, така че можете да получите позицията (индекса) на съвпадащите части.

Самият итератор не може да бъде отпечатан с print(), за да се получи съдържанието му. Ако използвате вградената функция next() или командата for, можете да получите съдържанието едно по едно.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

Той може да бъде превърнат в списък и с функцията list().

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

Ако искате да получите позицията на всички съвпадащи части, записът за разбиране на списък е по-удобен от list().

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

Итераторът изважда елементите в определен ред. Имайте предвид, че ако се опитате да извлечете още елементи след достигане на края, ще останете без нищо.

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

Заменете съответстващите части: sub(), subn()

С помощта на функцията sub() можете да замените съответстващата част с друг низ. Заместеният низ ще бъде върнат.

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

При групиране със скоби() съвпадналият низ може да се използва в заменения низ.

По подразбиране се поддържа следното: Имайте предвид, че за нормални низове, които не са необработени низове, трябва да се изпише обратна наклонена черта преди обратната наклонена черта, за да се избегне обратната наклонена черта.

\1Първата скоба
\2Втората скоба
\3Третата скоба
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
Ако дадете име на групата, като го напишете в началото на скобите на шаблона за регулярни изрази, можете да го зададете, като използвате името вместо числото, както е показано по-долу.
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

Аргументът count задава максималния брой замени. Ще бъде заменен само броят от лявата страна.

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn() връща кортеж от заместения низ (същия като върнатата стойност на sub()) и броя на заместените части (броя на частите, които отговарят на шаблона).

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

Методът за задаване на аргументи е същият като при sub(). Можете да използвате частта, групирана в скоби, или да посочите броя на аргументите.

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

Разделяне на низове с шаблони на регулярни изрази: split()

Сплит() разделя низа в частта, която отговаря на шаблона, и го връща като списък.

Обърнете внимание, че първото и последното съвпадение ще съдържат празни низове в началото и в края на получения списък.

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

Аргументът maxsplit задава максималния брой разделяния (части). Само броят от лявата страна ще бъде разделен.

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

Метасимволи на регулярни изрази, специални последователности и предупреждения в Python

Основните метасимволи на регулярните изрази (специални символи) и специални последователности, които могат да се използват в модула Python 3 re, са следните

метасимволсъдържание
.Всеки единичен символ, различен от нов ред (включително нов ред с флаг DOTALL)
^Началото на низа (съвпада и с началото на всеки ред с флага MULTILINE)
$Краят на низа (съвпада и с края на всеки ред с флага MULTILINE)
*Повтаряне на предишния модел повече от 0 пъти
+Повторете предишния модел поне веднъж.
?Повтаряне на предишния модел 0 или 1 път
{m}Повторете предишния модел m пъти
{m, n}Последният модел.m~nповторете
[]Набор от символи[]Съвпада с някой от тези знаци
|ИЛИA|BСъвпада с модел A или B
специална последователностсъдържание
\dДесетични числа в Unicode (ограничени до ASCII числа с флаг ASCII)
\D\dТоест обратното на това.
\sЗнаци за бели полета в Unicode (ограничени до знаци за бели полета в ASCII чрез флаг ASCII)
\S\sТоест обратното на това.
\wСимволи за думи Unicode и подчертавания (ограничени до буквено-цифрови символи ASCII и подчертавания с флаг ASCII)
\W\wТоест обратното на това.

Не всички от тях са изброени в тази таблица. Вижте официалната документация за пълен списък.

Също така имайте предвид, че някои от значенията са различни в Python 2.

Задаване на флага

Както е показано в таблицата по-горе, някои метасимволи и специални последователности променят режима си в зависимост от флага.

Тук са разгледани само основните знамена. За останалите вижте официалната документация.

Ограничено до ASCII символи: re.ASCII

\wПо подразбиране за низове в Python 3 това ще съответства и на двубайтови канджи, буквено-цифрови символи и т.н. Той не е еквивалентен на следния, защото не е стандартен регулярен израз.[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

Ако зададете re.ASCII за флаговете на аргумента във всяка функция или добавите следния флаг за вграждане в началото на низ от шаблони на регулярни изрази, той ще съответства само на ASCII символи (няма да съответства на двубайтови японски символи, буквено-цифрови символи и т.н.).
(?a)
В този случай следните две са еквивалентни.
\w=[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

Същото важи и при компилиране с re.compile(). Използвайте аргумента flags или inline flags.

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

ASCII се предлага и като кратка форма re. A. Можете да използвате.

print(re.ASCII is re.A)
# True

\W, обратното на \W, също се влияе от re.ASCII и инлайн флаговете.

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

Както и при \w, следните два символа по подразбиране съвпадат както с еднобайтови, така и с двубайтови символи, но се ограничават до еднобайтови символи, ако са зададени re.ASCII или флагове за вграждане.

  • Съвпадение на числата\d
  • съвпада с празно място\s
  • Съвпада с числа, които не са числа\D
  • Съответства на всяко място, което не е интервал.\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

Не се различават големи и малки букви:re.IGNORECASE

По подразбиране тя е чувствителна към малки и големи букви. За да съвпаднат и двете, трябва да включите в шаблона както главни, така и малки букви.

re.IGNORECASEАко това е посочено, ще се извърши сравнение без значение на регистрите. Еквивалентно на флага i в стандартните регулярни изрази.

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

Можете да използвате по-малко от или равно на.

  • вграден флаг(?i)
  • съкращениеre.I

Подберете началото и края на всеки ред:re.MULTILINE

^Метасимволите в този регулярен израз съвпадат с началото на низа.

По подразбиране се подбира само началото на целия низ, но следният начин ще подбере и началото на всеки ред. Еквивалентно на флага m в стандартните регулярни изрази.
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$Съответства на края на низа. По подразбиране се сравнява само краят на целия низ.
re.MULTILINEАко посочите тази стойност, тя ще съответства и на края на всеки ред.

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

Можете да използвате по-малко от или равно на.

  • вграден флаг(?m)
  • съкращениеre.M

Задаване на няколко флага

|Ако искате да активирате няколко флага едновременно, използвайте това. В случай на вградени флагове всеки символ трябва да бъде последван от буква, както е показано по-долу.
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

Жадни и нежадни съвпадения

Това е общ проблем с регулярните изрази, а не само проблем на Python, но ще пиша за него, защото имам склонност да си навличам неприятности.

По подразбиране следното е алчно съвпадение, което съвпада с най-дългия възможен низ.

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

Символът ? след него ще доведе до минимално съвпадение, което не е жадно, а съответства на най-краткия възможен низ.

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

Обърнете внимание, че алчното съвпадение по подразбиране може да съвпадне с неочаквани низове.

Copied title and URL