Kuidas kasutada Pythoni regulaaravaldiste moodulit re (match, search, sub jne.)

Äri

Tavapäraste väljendite töötlemiseks Pythonis kasutame standardraamatukogu re-moodulit. See võimaldab väljavõtteid eraldada, asendada ja jagada stringid, kasutades regulaaravaldiste mustreid.

Selles jaotises selgitame kõigepealt re-mooduli funktsioone ja meetodeid.

  • Regulaaravaldiste mustrite koostamine:compile()
  • mängu objekt
  • Kontrollida, kas stringi algus vastab, ekstrakt:match()
  • Kontrollige, kas vasted ei piirdu algusega:search()
  • Kontrollida, kas kogu string vastab:fullmatch()
  • Hankige nimekiri kõikidest sobivatest osadest:findall()
  • Hangib kõik sobivad osad iteraatorina:finditer()
  • Asendage sobiv osa:sub(),subn()
  • Stringide jagamine regulaaravaldiste mustritega:split()

Pärast seda selgitan metamärke (erimärke) ja regulaaravaldiste erijada, mida saab kasutada re-moodulis. Põhimõtteliselt on tegemist standardse regulaaravaldise süntaksiga, kuid olge ettevaatlik lipukeste (eriti re.ASCII) seadistamisega.

  • Regulaaravaldise metamärgid, erijärged ja hoiatused Pythonis
  • Lipu seadmine
    • Piiratud ASCII tähemärkidega:re.ASCII
    • Ei sõltu suur- ja väiketähtedest:re.IGNORECASE
    • Sobita iga rea algus ja lõpp:re.MULTILINE
    • Mitme lipu määramine
  • Ahned ja mitte-ahned matšid

Regulaarse väljendi mustri koostamine: compile()

Re-moodulis on kaks võimalust regulaaravaldiste töötlemiseks.

Käivita koos funktsiooniga

Esimene on funktsioon.re.match(),re.sub()Sellised funktsioonid on saadaval ekstraheerimise, asendamise ja muude protsesside teostamiseks, kasutades regulaarseid väljendusmustreid.

Funktsioonide üksikasju kirjeldatakse hiljem, kuid kõigis neis on esimene argument regulaaravaldise mustri string, millele järgneb töödeldav string ja nii edasi. Näiteks re.sub(), mis teostab asendamise, teine argument on asendusstring ja kolmas argument on töödeldav string.

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

Pange tähele, et [a-z] selles näites tähendab regulaaravaldise mustris mis tahes märki alates a-st kuni z-ni (st väiketähestikku) ja + tähendab eelmise mustri (antud juhul [a-z]) kordamist üks või mitu korda. [a-z]+ sobib mis tahes stringiga, mis kordab ühte või mitut väikse tähestiku märki.

. on metamärk (erimärk, millel on eriline tähendus) ja seda tuleb vältida kaldkriipsu abil.

Kuna regulaaravaldiste mustri stringid kasutavad sageli palju kaldkriipsu, on mugav kasutada toorest stringi nagu näites.

Käib regulaarse väljendusmudeli objekti meetodis

Teine viis regulaaravaldiste töötlemiseks re-moodulis on regulaaravaldiste mustri objektimeetod.

Kasutades re.compile(), saate koostada regulaaravaldise mustri stringi, et luua regulaaravaldise mustri objekt.

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()Näiteks võib sama protsessi nagu neid funktsioone täita regulaaravaldiste objektide meetoditega 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

Kõik allpool kirjeldatud re.xxx() funktsioonid on esitatud ka regulaaravaldise objekti meetoditena.

Kui te kordate protsessi, mis kasutab sama mustrit, on tõhusam genereerida regulaaravaldise objekt re.compile() abil ja kasutada seda ümberringi.

Järgnevas näidiskoodis kasutatakse funktsiooni mugavuse huvides ilma kompileerimiseta, kuid kui soovite sama mustrit korduvalt kasutada, on soovitatav see eelnevalt kompileerida ja käivitada see regulaaravaldise objekti meetodina.

mängu objekt

match(), search() jne. tagastavad vasteobjekti.

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

Sobitatud string ja positsioon saadakse järgmiste match-objekti meetodite abil.

  • Hankige mängu asukoht:start(),end(),span()
  • Hangib sobiva stringi:group()
  • Hankige iga rühma jaoks string:groups()
print(m.start())
# 0

print(m.end())
# 11

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

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

Kui ümbritsete regulaaravaldise mustri osa stringi sisse sulgudega(), töödeldakse seda osa grupina. Sellisel juhul saab iga rühmale vastava osa stringi rühmade() abil tuplina kätte.

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

Kontrollida, kas stringi algus vastab, väljavõte: match()

match() tagastab match-objekti, kui stringi algus vastab mustrile.

Nagu eespool mainitud, saab match-objekti kasutada sobiva alamstringi väljavõtmiseks või lihtsalt selle kontrollimiseks, kas vastavus on saavutatud.

match() kontrollib ainult algust. Kui alguses ei ole sobivat stringi, siis tagastab see 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

Kontrollida vasteid, mis ei piirdu algusega, väljavõte: search()

Nagu match(), tagastab see match-objekti, kui see vastab.

Kui on mitu kokkulangevat osa, tagastatakse ainult esimene kokkulangev osa.

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

Kui soovite saada kõik sobivad osad, kasutage findall() või finditer(), nagu allpool kirjeldatud.

Kontrollida, kas kogu string vastab: fullmatch()

Selleks, et kontrollida, kas kogu string vastab regulaaravaldise mustrile, kasutage funktsiooni fullmatch(). See on kasulik näiteks selleks, et kontrollida, kas string sobib e-posti aadressiks või mitte.

Kui kogu string vastab, tagastatakse match-objekt.

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

Kui on sobimatuid osi (ainult osaline kokkulangevus või ei ole üldse kokkulangevust), tagastatakse None.

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

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

Funktsioon fullmatch() lisati Python 3.4. Kui soovite sama teha ka varasemates versioonides, kasutage match() ja lõpus sobivat metamärki $. Kui kogu string algusest lõpuni ei vasta, siis tagastab see None.

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

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

Saada nimekiri kõikidest sobivatest osadest: findall()

findall() tagastab kõigi sobivate alamsõnade loendi. Pange tähele, et nimekirja elemendid ei ole mitte vasteobjektid, vaid stringid.

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

Vastavate osade arvu saab kontrollida, kasutades sisseehitatud funktsiooni len(), mis tagastab nimekirja elementide arvu.

print(len(result))
# 3

Sulgudega() rühmitamine regulaaravaldise mustris tagastab topelite loendi, mille elemendid on iga rühma stringid. See on samaväärne group() funktsiooniga match objektis.

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

Grupi sulgudes () võib olla nested, nii et kui soovite saada ka kogu vastet, siis lihtsalt sulgege kogu vaste sulgudesse ().

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

Kui vastavust ei leita, tagastatakse tühi tupel.

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

Hangi kõik sobivad osad iteraatorina: finditer()

finditer() tagastab kõik sobivad osad iteraatorina. Elemendid ei ole stringid nagu findall(), vaid vastavad objektid, nii et saad sobivate osade asukoha (indeksi).

Iteraatorit ennast ei saa print() abil välja trükkida, et saada selle sisu. Kui kasutate sisseehitatud funktsiooni next() või for-avaldust, saate sisu ükshaaval kätte.

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

Seda saab konverteerida list() abil ka loeteluks.

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)

Kui soovite saada kõigi kokkulangevate osade positsiooni, on loetelu mõistmise märkimine mugavam kui list().

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

Iteraator võtab elemendid välja järjekorras. Pange tähele, et kui püüate pärast lõppu veel elemente välja võtta, ei jää teil midagi alles.

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

Asendage sobivad osad: sub(), subn()

Kasutades sub(), saate sobitatud osa asendada teise stringiga. Tagastatakse asendatud string.

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

Sulgude() abil rühmitamisel saab sobitatud stringi kasutada asendatavas stringis.

Vaikimisi toetatakse järgmist: Pange tähele, et tavaliste stringide puhul, mis ei ole toorstringid, tuleb tagurpidi kaldkriipsu vältimiseks esitada tagurpidi kaldkriipsu ees.

\1Esimene sulgemine
\2Teine sulgemine
\3Kolmas sulgemine
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>
Kui annate rühmale nime, kirjutades selle regulaaravaldise mustri sulgude algusesse, saate seda määrata numbri asemel nime kasutades, nagu allpool näidatud.
\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 määrab asenduste maksimaalse arvu. Asendatakse ainult vasakpoolne arv.

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() tagastab tupli, mis koosneb asendatud stringist (sama, mis sub() tagastusväärtus) ja asendatud osade arvust (arv, mis vastas mustrile).

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

Argumentide määramise meetod on sama nagu sub(). Võite kasutada sulgudes grupeeritud osa või määrata argumentide arvu.

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)

Stringide jagamine regulaaravaldiste mustritega: split()

split() jagab stringi selles osas, mis vastab mustrile, ja tagastab selle loeteluna.

Pange tähele, et esimene ja viimane kokkulangevus sisaldab tühja stringi tulemuseks oleva loendi alguses ja lõpus.

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 määrab maksimaalse arvu jagamisi (tükke). Jagatakse ainult vasakpoolne arv.

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

Regulaaravaldise metamärgid, erijärged ja hoiatused Pythonis

Peamised regulaaravaldise metamärgid (erimärgid) ja erijärjestused, mida saab kasutada Python 3 re moodulis, on järgmised

metatähissisu
.mis tahes üksikmärk peale uue rea (sealhulgas uus rida koos DOTALL-märgiga)
^stringi algus (vastab ka iga rea algusele, millel on MULTILINE lipukene)
$Stringi lõpp (sobib ka iga rea lõppu MULTILINE lipukesega)
*Korda eelmist mustrit rohkem kui 0 korda.
+Korrake eelmist mustrit vähemalt üks kord.
?Korda eelmist mustrit 0 või 1 korda.
{m}Korda eelmist mustrit m korda
{m, n}Viimane muster.m~nkordus
[]Tähemärkide kogum[]Vastab ükskõik millisele neist märkidest
|VÕIA|BVastab kas A- või B-mustrile
spetsiaalne jadasisu
\dUnicode kümnendarvud (piiratud ASCII numbritega ASCII lipuga)
\D\dSee tähendab vastupidist.
\sUnicode'i tühimärgid (ASCII lipuga piiratud ASCII tühimärkidega)
\S\sSee tähendab vastupidist.
\wUnicode'i sõnamärgid ja allajooned (piiratud ASCII tähtnumbriliste tähemärkide ja allajoonega ASCII lipu järgi)
\W\wSee tähendab vastupidist.

Kõik need ei ole käesolevas tabelis loetletud. Täielik nimekiri on esitatud ametlikus dokumentatsioonis.

Pange tähele, et mõned tähendused on Python 2-s teistsugused.

Lipu seadmine

Nagu ülaltoodud tabelis näidatud, muudavad mõned metamärgid ja spetsiaalsed järjestused oma režiimi sõltuvalt lipust.

Siin on hõlmatud ainult peamised lipud. Ülejäänu kohta vaata ametlikku dokumentatsiooni.

Piiratud ASCII tähemärkidega: re.ASCII

\wSee sobib ka kahebaidiliste kanjide, tähtnumbriliste märkide jne jaoks vaikimisi Python 3 stringide puhul. See ei ole samaväärne, sest see ei ole standardne regulaaravaldis.[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

Kui te määrate igas funktsioonis argumendi lipudeks re.ASCII või lisate regulaaravaldise mustri stringi algusesse järgmise inline lipu, vastab see ainult ASCII-märkidele (see ei vasta kahebaidulistele jaapani tähtedele, tähtnumbrilistele märkidele jne).
(?a)
Sellisel juhul on järgmised kaks samaväärsed.
\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

Sama kehtib ka kompileerimisel re.compile() abil. Kasutage argumenti flags või 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 on saadaval ka lühivormina re. A. Võite kasutada kas.

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

\W, mis on \W vastand, on samuti mõjutatud re.ASCII ja inline lipukestest.

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

Nagu \w puhul, sobivad järgmised kaks vaikimisi nii ühe- kui ka kahebaidiliste märkidega, kuid piirduvad ühebaidiliste märkidega, kui on määratud re.ASCII või inline lipud.

  • Sobita numbreid\d
  • Vastab tühjale kohale\s
  • Vastab muudele kui numbritele\D
  • Sobib mis tahes mitte-ruumiga.\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

Ei sõltu suur- ja väiketähtedest:re.IGNORECASE

Vaikimisi on see suur- ja väiketähtede suhtes tundlik. Mõlema sobitamiseks peate musterisse lisama nii suur- kui ka väiketähti.

re.IGNORECASEKui see on määratud, siis vastab see tundmatuseni. Võrreldes standardsete regulaaravaldiste i lipuga.

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

Võite kasutada vähem või võrdne.

  • inline-lipp(?i)
  • lühendre.I

Sobita iga rea algus ja lõpp:re.MULTILINE

^Selle regulaaravaldise metamärgid vastavad stringi algusele.

Vaikimisi sobitatakse ainult kogu stringi algus, kuid järgnevalt sobitatakse ka iga rea algus. Võrreldes m lipuga tavalistes regulaaravaldistes.
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']

$Sobib stringi lõppu. Vaikimisi sobitatakse ainult kogu stringi lõppu.
re.MULTILINEKui te määrate selle, vastab see ka iga rea lõppu.

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

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

Võite kasutada vähem või võrdne.

  • inline-lipp(?m)
  • lühendre.M

Mitme lipu määramine

|Kui soovite lubada korraga mitut lippu, kasutage seda. Inline-lippude puhul peab igale tähemärgile järgnema täht, nagu allpool näidatud.
(?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']

Ahned ja mitte-ahned matšid

See on üldine probleem regulaaravaldiste puhul, mitte ainult Pythoni probleem, aga ma kirjutan sellest, sest see kipub mind hätta ajama.

Vaikimisi on järgmine ahne kokkulangevus, mis vastab pikimale võimalikule stringile.

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

Selle järel olev ? annab tulemuseks mitte-halva, minimaalse kokkulangevuse, mis vastab lühimale võimalikule stringile.

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

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

Pange tähele, et vaikimisi ahne kokkulangevus võib sobida ootamatute stringidega.