Kako uporabljati modul rednih izrazov Python re (match, search, sub itd.)

Posel

Za obdelavo regularnih izrazov v Pythonu uporabimo modul re iz standardne knjižnice. Omogoča pridobivanje, nadomeščanje in deljenje nizov z uporabo vzorcev regularnih izrazov.

V tem razdelku bomo najprej razložili funkcije in metode modula re.

  • Sestavljanje vzorcev regularnih izrazov:compile()
  • predmet ujemanja
  • Preveri, ali se začetek niza ujema, izvleček:match()
  • Preverite, ali se ujemajo z začetkom:search()
  • Preveri, ali se ujema celoten niz:fullmatch()
  • Pridobite seznam vseh ustreznih delov:findall()
  • Pridobi vse ujemajoče se dele kot iterator:finditer()
  • Zamenjajte ustrezen del:sub(),subn()
  • Deljenje nizov z vzorci regularnih izrazov:split()

Nato bom razložil meta znake (posebne znake) in posebna zaporedja regularnih izrazov, ki jih je mogoče uporabiti v modulu re. V osnovi gre za standardno sintakso regularnih izrazov, vendar bodite previdni pri nastavljanju zastavic (zlasti re.ASCII).

  • Metaznaki regularnih izrazov, posebna zaporedja in opozorila v programu Python
  • Nastavitev zastave
    • Omejeno na znake ASCII:re.ASCII
    • Ni občutljivo na velikost črk:re.IGNORECASE
    • Ujemite začetek in konec vsake vrstice:re.MULTILINE
    • Določite več zastavic
  • Pohlepne in nepožrešne tekme

Sestavi vzorec regularnega izraza: compile()

Obdelavo regularnih izrazov v modulu re lahko izvedete na dva načina.

Delujte s funkcijo

Prva je funkcija.re.match(),re.sub()Funkcije, kot so te, so na voljo za izvajanje izločanja, nadomeščanja in drugih postopkov z uporabo vzorcev regularnih izrazov.

Podrobnosti funkcij bodo opisane pozneje, vendar je pri vseh prvi argument niz vzorca regularnega izraza, sledi niz, ki ga je treba obdelati, in tako naprej. Na primer, v funkciji re.sub(), ki izvaja zamenjavo, je drugi argument niz za zamenjavo, tretji argument pa niz, ki ga je treba obdelati.

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

Upoštevajte, da [a-z] v vzorcu regularnega izraza v tem primeru pomeni katerikoli znak od a do z (tj. mala abeceda), + pa pomeni, da prejšnji vzorec (v tem primeru [a-z]) ponovite enkrat ali večkrat. Vzorec [a-z]+ ustreza kateremu koli nizu, ki ponavlja enega ali več znakov male abecede.

. je meta znak (znak s posebnim pomenom) in ga je treba izogniti s povratno poševnico.

Ker nizi vzorcev regularnih izrazov pogosto uporabljajo veliko povratnih lomk, je priročno uporabiti neobdelane nize, kot je prikazano v tem primeru.

Deluje v metodi objekta vzorca regularnega izraza

Drugi način obdelave regularnih izrazov v modulu re je objektna metoda vzorca regularnih izrazov.

S funkcijo re.compile() lahko sestavite niz vzorcev regularnih izrazov in ustvarite objekt vzorca regularnega izraza.

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()Enak postopek kot te funkcije se lahko na primer izvede kot metode match(),sub() objektov regularnih izrazov.

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

Vse spodaj opisane funkcije re.xxx() so na voljo tudi kot metode objekta regularnega izraza.

Če ponavljate postopek, ki uporablja isti vzorec, je učinkovitejše ustvariti objekt regularnega izraza s funkcijo re.compile() in ga uporabiti naokrog.

V naslednjem vzorcu kode je funkcija zaradi priročnosti uporabljena brez kompiliranja, če pa želite večkrat uporabiti isti vzorec, je priporočljivo, da jo predhodno kompilirate in izvedete kot metodo objekta regularnega izraza.

predmet ujemanja

match(), search() itd. vrnejo predmet match.

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'>

Ujemani niz in položaj se pridobita z naslednjimi metodami objekta match.

  • Pridobi lokacijo tekme:start(),end(),span()
  • Pridobi ujemajoči se niz:group()
  • Pridobi niz za vsako skupino:groups()
print(m.start())
# 0

print(m.end())
# 11

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

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

Če del vzorca regularnega izraza zaprete v niz z oklepaji(), bo del obdelan kot skupina. V tem primeru lahko niz dela, ki se ujema z vsako skupino v grup(), dobite kot tuple.

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')

preveri, ali se začetek niza ujema, izvleček: match()

match() vrne predmet match, če se začetek niza ujema z vzorcem.

Kot smo že omenili, lahko objekt match uporabimo za izpis ujemajočega se podreza ali pa preprosto preverimo, ali je prišlo do ujemanja.

match() preveri samo začetek. Če na začetku ni ustreznega niza, vrne 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

preverjanje ujemanj, ki niso omejena na začetek, izvleček: search()

Podobno kot funkcija match() vrne predmet match, če se ujema.

Če je več ujemajočih se delov, bo vrnjen samo prvi ujemajoči se del.

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'>

Če želite pridobiti vse ujemajoče se dele, uporabite funkcijo findall() ali finditer(), kot je opisano spodaj.

Preverite, ali se ujema celoten niz: fullmatch()

Če želite preveriti, ali se celoten niz ujema z vzorcem regularnega izraza, uporabite funkcijo fullmatch(). To je uporabno na primer za preverjanje, ali je niz veljaven kot e-poštni naslov ali ne.

Če se ujema celoten niz, se vrne predmet ujemanja.

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'>

Če se deli ne ujemajo (samo delna ujemanja ali sploh nobeno ujemanje), se vrne vrednost None.

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

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

Funkcija fullmatch() je bila dodana v Pythonu 3.4. Če želite enako narediti v prejšnjih različicah, uporabite match() in ustrezni meta znak $ na koncu. Če se celoten niz od začetka do konca ne ujema, vrne None.

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

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

Pridobi seznam vseh ujemajočih se delov: findall()

funkcija findall() vrne seznam vseh ustreznih podrejencev. Upoštevajte, da elementi seznama niso objekti ujemanja, temveč nizi.

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']

Število ujemajočih se delov lahko preverite z vgrajeno funkcijo len(), ki vrne število elementov na seznamu.

print(len(result))
# 3

Združevanje v skupine z oklepaji() v vzorcu regularnega izraza vrne seznam nizov, katerih elementi so nizi vsake skupine. To je enakovredno funkciji groups() v objektu match.

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

Skupinski oklepaji () so lahko vgnezdeni, zato, če želite dobiti tudi celotno ujemanje, celotno ujemanje zapišite v oklepaj ().

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')]

Če ni najdeno nobeno ujemanje, se vrne prazen tuple.

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

Pridobi vse ustrezne dele kot iterator: finditer()

finditer() vrne vse ujemajoče se dele kot iterator. Elementi niso nizi kot pri funkciji findall(), temveč objekti ujemanja, zato lahko dobite položaj (indeks) ujetih delov.

Iteratorja samega ni mogoče izpisati s funkcijo print(), da bi dobili njegovo vsebino. Če uporabite vgrajeno funkcijo next() ali stavek for, lahko vsebino dobite eno za drugo.

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'>

V seznam ga lahko pretvorite tudi s funkcijo 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)

Če želite pridobiti položaj vseh ujemajočih se delov, je zapis za razumevanje seznama priročnejši od zapisa list().

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

Iterator vzame elemente po vrstnem redu. Upoštevajte, da če boste po koncu poskušali izločiti več elementov, vam ne bo ostalo nič.

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))
# []

Zamenjajte ustrezne dele: sub(), subn()

S funkcijo sub() lahko ujemajoči se del nadomestite z drugim nizom. Vrnjen bo zamenjani niz.

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'>

Pri združevanju z oklepaji() lahko v nadomeščenem nizu uporabimo usklajeni niz.

Privzeto so podprte naslednje možnosti: Pri običajnih nizih, ki niso surovi nizi, je treba pred povratno poševnico navesti povratno poševnico, da se ta izogne povratni poševnici.

\1Prvi oklepaj
\2Drugi oklepaj
\3Tretji oklepaj
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>
Če skupino poimenujete tako, da to zapišete na začetku oklepajev vzorca regularnega izraza, jo lahko določite z imenom namesto s številko, kot je prikazano spodaj.
\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

Argument count določa največje število zamenjav. Zamenjano bo samo število z leve strani.

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() vrne tuple nadomeščenega niza (enako kot povratna vrednost sub()) in število nadomeščenih delov (število delov, ki ustrezajo vzorcu).

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

Način določanja argumentov je enak kot pri sub(). Uporabite lahko del, združen v oklepajih, ali določite število argumentov.

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)

Deljenje nizov z vzorci regularnih izrazov: split()

split() razdeli niz na delu, ki ustreza vzorcu, in ga vrne kot seznam.

Upoštevajte, da bosta prvo in zadnje ujemanje vsebovala prazne nize na začetku in koncu seznama.

s = '111aaa222bbb333'

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

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

Argument maxsplit določa največje število delitev (kosov). Razdeljeno bo samo število z leve strani.

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

Metaznaki regularnih izrazov, posebna zaporedja in opozorila v programu Python

Glavni meta znaki regularnih izrazov (posebni znaki) in posebna zaporedja, ki jih je mogoče uporabiti v modulu Python 3 re, so naslednji

metaznakvsebina
.katerikoli posamezni znak razen nove vrstice (vključno z novo vrstico z zastavico DOTALL).
^Začetek niza (ustreza tudi začetku vsake vrstice z zastavico MULTILINE)
$Konec niza (ustreza tudi koncu vsake vrstice z zastavico MULTILINE)
*Prejšnji vzorec ponovite več kot 0-krat.
+Prejšnji vzorec ponovite vsaj enkrat.
?Ponovite prejšnji vzorec 0- ali 1-krat.
{m}Ponovite prejšnji vzorec m-krat.
{m, n}Zadnji vzorec.m~nponovite
[]Nabor znakov[]ustreza kateremu koli od teh znakov
|ALIA|BUjema se z vzorcem A ali B
posebno zaporedjevsebina
\ddecimalna števila Unicode (omejena na števila ASCII z zastavico ASCII)
\D\dPomeni nasprotno od tega.
\sbeli znaki Unicode (omejeni na bele znake ASCII z zastavico ASCII)
\S\sPomeni nasprotno od tega.
\wBesedni znaki Unicode in podčrtaji (omejeni na alfanumerične znake ASCII in podčrtane znake z zastavico ASCII)
\W\wPomeni nasprotno od tega.

V tej preglednici niso navedeni vsi. Celoten seznam je na voljo v uradni dokumentaciji.

Upoštevajte tudi, da so nekateri pomeni v Pythonu 2 drugačni.

Nastavitev zastave

Kot je prikazano v zgornji tabeli, nekateri meta znaki in posebna zaporedja spreminjajo svoj način glede na zastavico.

Tu so zajete le glavne zastave. Za ostale glejte uradno dokumentacijo.

Omejeno na znake ASCII: re.ASCII

\wPrivzeto se bo to ujemalo tudi z dvobajtnimi kanji, alfanumeričnimi znaki itd. za nize Python 3. Ni enakovreden naslednjemu, ker ni standardni regularni izraz.[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

Če za zastavice argumentov v vsaki funkciji določite re.ASCII ali na začetek niza vzorcev regularnih izrazov dodate naslednjo zastavico v vrstici, se bodo ujemali samo znaki ASCII (ne bodo se ujemali dvobajtni japonski znaki, alfanumerični znaki itd.).
(?a)
V tem primeru sta naslednji dve enakovredni.
\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

Enako velja za sestavljanje s funkcijo re.compile(). Uporabite argument flags ali 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 je na voljo tudi kot kratka oblika re. A. Uporabite lahko.

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

Na \W, ki je nasprotje \W, vplivata tudi re.ASCII in inline zastave.

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'>

Tako kot pri \w se naslednja dva privzeto ujemata z enobajtnimi in dvobajtnimi znaki, vendar sta omejena na enobajtne znake, če so določene oznake re.ASCII ali inline.

  • Ujemanje številk\d
  • ujema prazen prostor\s
  • ujema številke, ki niso številke\D
  • Ujema se s katerim koli znakom, ki ni presledek.\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

Ni občutljivo na velikost črk:re.IGNORECASE

Privzeto je občutljiv na velike in male črke. Če želite, da se ujemata obe vrsti črk, morate v vzorec vključiti tako velike kot male črke.

re.IGNORECASEČe je to določeno, se bo ujemalo brez upoštevanja velikih in malih črk. Enakovredno oznaki i v standardnih regularnih izrazih.

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'>

Uporabite lahko manj kot ali enako.

  • inline zastavica(?i)
  • okrajšavare.I

Ujemite začetek in konec vsake vrstice:re.MULTILINE

^Meta znaki v tem regularnem izrazu se ujemajo z začetkom niza.

Privzeto se ujema le začetek celotnega niza, vendar se v naslednjem primeru ujema tudi začetek vsake vrstice. Enakovredno oznaki m v standardnih regularnih izrazih.
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']

$Ujema konec niza. Privzeto se ujema samo konec celotnega niza.
re.MULTILINEČe to določite, se bo ujemal tudi s koncem vsake vrstice.

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

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

Uporabite lahko manj kot ali enako.

  • inline zastavica(?m)
  • okrajšavare.M

Določite več zastavic

|Če želite omogočiti več zastavic hkrati, uporabite to. Pri vrstičnih zastavicah mora vsakemu znaku slediti črka, kot je prikazano spodaj.
(?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']

Pohlepne in nepožrešne tekme

To je splošna težava z regularnimi izrazi, ne le težava v Pythonu, vendar bom o njej pisal, ker me običajno spravi v težave.

Privzeto je naslednje ujemanje požrešno in ustreza najdaljšemu možnemu nizu.

  • *
  • +
  • ?
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

Za znakom ? se prikaže minimalno ujemanje, ki ni pohlepno in ustreza najkrajšemu možnemu nizu.

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

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

Upoštevajte, da lahko privzeto požrešno ujemanje ustreza nepričakovanim nizom.