Sådan bruger du Pythons modul for regulære udtryk re (match, search, sub osv.)

Forretning

For at udføre behandling af regulære udtryk i Python bruger vi re-modulet fra standardbiblioteket. Det giver dig mulighed for at udtrække, erstatte og opdele strenge ved hjælp af regulære udtryksmønstre.

I dette afsnit vil vi først forklare funktionerne og metoderne i re-modulet.

  • Kompilering af mønstre for regulære udtryk:compile()
  • match objekt
  • Kontroller, om begyndelsen af strengen passer, uddrag:match()
  • Tjek for kampe, der ikke er begrænset til begyndelsen:search()
  • Kontroller, om hele strengen passer:fullmatch()
  • Få en liste over alle matchende dele:findall()
  • Hent alle matchende dele som en iterator:finditer()
  • Udskift den tilsvarende del:sub(),subn()
  • Opdeling af strenge med regulære udtryksmønstre:split()

Derefter vil jeg forklare meta-tegn (specialtegn) og specielle sekvenser af regulære udtryk, som kan bruges i re-modulet. Grundlæggende er det standard syntaksen for regulære udtryk, men vær forsigtig med at sætte flag (især re.ASCII).

  • Metakendetegn for regulære udtryk, specielle sekvenser og forbehold i Python
  • Indstilling af flaget
    • Begrænset til ASCII-tegn:re.ASCII
    • Ikke skille mellem store og små bogstaver:re.IGNORECASE
    • Find begyndelsen og slutningen af hver linje:re.MULTILINE
    • Angiv flere flag
  • Grådige og ikke-grådige kampe

Kompilere det regulære udtryksmønster: compile()

Der er to måder at udføre behandling af regulære udtryk på i re-modulet.

Kør med funktion

Den første er en funktion.re.match(),re.sub()Funktioner som disse er tilgængelige til at udføre udtrækning, erstatning og andre processer ved hjælp af mønstre i regulære udtryk.

Detaljerne i funktionerne vil blive beskrevet senere, men i dem alle er det første argument strengen i det regulære udtryksmønster, efterfulgt af den streng, der skal behandles osv. I re.sub(), som udfører substitution, er det andet argument f.eks. substitutionstrengen, og det tredje argument er den streng, der skal behandles.

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

Bemærk, at [a-z] i det regulære udtryksmønster i dette eksempel betyder ethvert tegn fra a til z (dvs. alfabetet med små bogstaver), og + betyder, at det tidligere mønster (i dette tilfælde [a-z]) gentages en eller flere gange. [a-z]+ passer til enhver streng, der gentager et eller flere alfabetiske tegn med små bogstaver.

. er et meta-tegn (et tegn med en særlig betydning) og skal undviges med en skråstreg.

Da strenge med regulære udtryksmønstre ofte bruger mange backslashes, er det praktisk at bruge rå strenge som i eksemplet.

Kører i en metode i et mønsterobjekt for regulære udtryk

Den anden måde at behandle regulære udtryk på i re-modulet er metoden til behandling af mønsterobjekter for regulære udtryk.

Ved hjælp af re.compile() kan du kompilere en streng med et regulært udtryksmønster for at oprette et objekt med et regulært udtryksmønster.

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()Den samme proces som disse funktioner kan f.eks. udføres som metoder match(),sub() for regulære udtryksobjekter.

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

Alle de re.xxx()-funktioner, der er beskrevet nedenfor, er også tilgængelige som metoder i objektet for regulære udtryk.

Hvis du gentager en proces, der bruger det samme mønster, er det mere effektivt at generere et regulært udtryksobjekt med re.compile() og bruge det rundt omkring.

I den følgende eksempelkode bruges funktionen uden kompilering for nemheds skyld, men hvis du vil bruge det samme mønster gentagne gange, anbefales det at kompilere den på forhånd og udføre den som en metode i et regulært udtryksobjekt.

match objekt

match(), search() osv. returnerer et matchobjekt.

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

Den matchede streng og positionen fås ved hjælp af følgende metoder for match-objektet.

  • Få oplyst kampens placering:start(),end(),span()
  • Hent den matchede streng:group()
  • Hent strengen for hver gruppe:groups()
print(m.start())
# 0

print(m.end())
# 11

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

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

Hvis du omslutter en del af et regulært udtryksmønster i en streng med parenteser(), vil delen blive behandlet som en gruppe. I dette tilfælde kan strengen af den del, der matcher hver gruppe i groups(), fås som en tupel.

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

Kontroller, om begyndelsen af en streng passer, uddrag: match()

match() returnerer et match-objekt, hvis begyndelsen af strengen passer til mønsteret.

Som nævnt ovenfor kan match-objektet bruges til at udtrække den matchede delstreng eller blot til at kontrollere, om der blev fundet et match.

match() vil kun kontrollere begyndelsen. Hvis der ikke er nogen matchende streng i begyndelsen, returnerer den 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

Tjek for resultater, der ikke er begrænset til begyndelsen, uddrag: search()

Ligesom match() returnerer den et matchobjekt, hvis det passer.

Hvis der er flere matchende dele, returneres kun den første matchende 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'>

Hvis du ønsker at få alle matchende dele, skal du bruge findall() eller finditer() som beskrevet nedenfor.

Kontroller, om hele strengen passer: fullmatch()

Hvis du vil kontrollere, om hele strengen passer til det regulære udtryksmønster, skal du bruge fullmatch(). Dette er f.eks. nyttigt for at kontrollere, om en streng er gyldig som en e-mail-adresse eller ej.

Hvis hele strengen passer, returneres et matchobjekt.

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

Hvis der er dele, der ikke passer sammen (kun delvis eller slet ikke passer sammen), returneres None.

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

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

Fullmatch() blev tilføjet i Python 3.4. Hvis du vil gøre det samme i tidligere versioner, skal du bruge match() og et matchende meta-tegn $ i slutningen. Hvis hele strengen fra start til slut ikke matcher, returnerer den None.

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

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

Få en liste over alle matchende dele: findall()

findall() returnerer en liste over alle matchende understrenge. Bemærk, at elementerne i listen ikke er matchobjekter, men strenge.

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

Antallet af matchede dele kan kontrolleres ved hjælp af den indbyggede funktion len(), som returnerer antallet af elementer i listen.

print(len(result))
# 3

Gruppering med parenteser() i et regulært udtryksmønster returnerer en liste af tupler, hvis elementer er strengene i hver gruppe. Dette svarer til groups() i matchobjektet.

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

Gruppens parenteser () kan være indlejret i hinanden, så hvis du også vil have hele matchet med, skal du blot omslutte hele matchet i parenteser ().

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

Hvis der ikke findes nogen match, returneres en tom tuple.

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

Hent alle matchende dele som en iterator: finditer()

finditer() returnerer alle matchende dele som en iterator. Elementerne er ikke strenge som findall(), men matchobjekter, så du kan få positionen (indekset) for de matchede dele.

Selve iteratoren kan ikke udskrives med print() for at få dens indhold. Hvis du bruger den indbyggede funktion next() eller for-erklæringen, kan du få indholdet en efter en.

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

Den kan også konverteres til en liste med 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)

Hvis du ønsker at få positionen for alle matchende dele, er list comprehension notation mere praktisk end list().

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

Iteratoren tager elementer ud i rækkefølge. Bemærk, at hvis du forsøger at udtage flere elementer, efter at du har nået slutningen, vil du ikke få noget tilbage.

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

Udskift de tilsvarende dele: sub(), subn()

Ved hjælp af sub() kan du erstatte den matchede del med en anden streng. Den erstattede streng returneres.

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

Når du grupperer med parentes(), kan den matchede streng bruges i den erstattede streng.

Som standard understøttes følgende: Bemærk, at for normale strenge, der ikke er rå strenge, skal der angives en skråstreg før skråstregen for at undslippe skråstregen.

\1Den første parentes
\2Den anden parentes
\3Den tredje parentes
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>
Hvis du navngiver gruppen ved at skrive dette i begyndelsen af parentesen i det regulære udtryksmønster, kan du angive den ved hjælp af navnet i stedet for nummeret, som vist nedenfor.
\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

Argumentet count angiver det maksimale antal erstatninger. Kun tallet fra venstre side vil blive erstattet.

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() returnerer en tupel af den erstattede streng (samme som returværdien af sub()) og antallet af erstattede dele (antallet af dele, der passede til mønstret).

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

Metoden til angivelse af argumenter er den samme som sub(). Du kan bruge den del, der er grupperet i parenteser, eller angive antallet af argumenter.

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)

Opdeling af strenge med regelmæssige udtryksmønstre: split()

split() opdeler strengen ved den del, der passer til mønsteret, og returnerer den som en liste.

Bemærk, at det første og sidste match vil indeholde tomme strenge i begyndelsen og slutningen af den resulterende liste.

s = '111aaa222bbb333'

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

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

Argumentet maxsplit angiver det maksimale antal splits (stykker). Kun tallet fra venstre side vil blive delt.

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

Metakendetegn for regulære udtryk, specielle sekvenser og forbehold i Python

De vigtigste meta-tegn for regulære udtryk (specialtegn) og specielle sekvenser, der kan bruges i Python 3 re-modulet, er som følger

metakendetegnindhold
.Ethvert andet enkelt tegn end en newline (herunder en newline med DOTALL-flaget)
^Begyndelsen af strengen (passer også til begyndelsen af hver linje med MULTILINE-flaget)
$Slutningen af strengen (svarer også til slutningen af hver linje med MULTILINE-flaget)
*Gentag det foregående mønster mere end 0 gange
+Gentag det foregående mønster mindst én gang.
?Gentag det foregående mønster 0 eller 1 gang
{m}Gentag det foregående mønster m gange
{m, n}Det sidste mønster.m~ngentag
[]Et sæt af tegn[]Matcher et af disse tegn
|ELLERA|BPasser til enten A- eller B-mønster
særlig rækkefølgeindhold
\dUnicode decimaltal (begrænset til ASCII-tal ved hjælp af ASCII-flag)
\D\dDet vil sige det modsatte af dette.
\sUnicode-whitespace-tegn (begrænset til ASCII-whitespace-tegn ved hjælp af ASCII-flag)
\S\sDet vil sige det modsatte af dette.
\wUnicode-ordtegn og understregninger (begrænset til ASCII-alfanumeriske tegn og understregninger ved ASCII-flag)
\W\wDet vil sige det modsatte af dette.

De er ikke alle opført i denne tabel. Se den officielle dokumentation for en komplet liste.

Bemærk også, at nogle af betydningerne er anderledes i Python 2.

Indstilling af flaget

Som det fremgår af tabellen ovenfor, ændrer nogle meta-tegn og specielle sekvenser deres tilstand afhængigt af flaget.

Kun de vigtigste flag er dækket her. Se den officielle dokumentation for resten.

Begrænset til ASCII-tegn: re.ASCII

\wDette vil også matche dobbelt-byte kanji, alfanumeriske tegn osv. som standard for Python 3-strenge. Det svarer ikke til følgende, fordi det ikke er et standard regulært udtryk.[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

Hvis du angiver re.ASCII som argumentflag i hver funktion, eller hvis du tilføjer følgende inline-flag i begyndelsen af mønsterstrengen for regulære udtryk, vil den kun matche ASCII-tegn (den vil ikke matche dobbelt-byte japansk, alfanumeriske tegn osv.).
(?a)
I dette tilfælde svarer de to følgende til hinanden.
\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

Det samme gælder, når du kompilerer med re.compile(). Brug argumentet flags eller 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 er også tilgængelig som den korte form re. A. Du kan bruge enten.

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

\W, det modsatte af \W, påvirkes også af re.ASCII- og inline-flagene.

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

Som med \w matcher de følgende to som standard både single-byte- og double-byte-tegn, men er begrænset til single-byte-tegn, hvis re.ASCII- eller inline-flagene er angivet.

  • Match tallene\d
  • Matcher et tomrum\s
  • Matcher ikke-numre\D
  • Passer til alle tegn uden mellemrum.\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

Ikke skille mellem store og små bogstaver:re.IGNORECASE

Som standard er den skivensitiv. Hvis du vil matche begge dele, skal du inkludere både store og små bogstaver i mønsteret.

re.IGNORECASEHvis dette er angivet, vil der ikke blive taget hensyn til store og små bogstaver. Svarer til i-flaget i standard regulære udtryk.

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

Du kan bruge mindre end eller lig med.

  • inline-flag(?i)
  • forkortelsere.I

Find begyndelsen og slutningen af hver linje:re.MULTILINE

^Meta-tegnene i dette regulære udtryk passer til begyndelsen af strengen.

Som standard matches kun begyndelsen af hele strengen, men følgende vil også matche begyndelsen af hver linje. Svarer til m-flaget i standard regulære udtryk.
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']

$Passer til slutningen af strengen. Som standard er det kun slutningen af hele strengen, der matches.
re.MULTILINEHvis du angiver dette, vil det også passe til slutningen af hver linje.

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

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

Du kan bruge mindre end eller lig med.

  • inline-flag(?m)
  • forkortelsere.M

Angiv flere flag

|Hvis du vil aktivere flere flag på samme tid, skal du bruge dette. I tilfælde af inline-flag skal hvert tegn efterfølges af et bogstav som vist nedenfor.
(?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']

Grådige og ikke-grådige kampe

Dette er et generelt problem med regulære udtryk, ikke kun et problem med Python, men jeg vil skrive om det, fordi det har tendens til at give mig problemer.

Som standard er følgende et greedy match, som matcher den længst mulige streng.

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

? efter det vil resultere i et ikke-grådigt, minimalt match, der matcher den kortest mulige streng.

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

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

Bemærk, at standard-greedy-matchet kan matche uventede strenge.

Copied title and URL