Python Language
Reguliere expressies (Regex)
Zoeken…
Invoering
Python maakt reguliere expressies beschikbaar via de re
module.
Reguliere expressies zijn combinaties van tekens die worden geïnterpreteerd als regels voor overeenkomende substrings. De uitdrukking 'amount\D+\d+'
komt bijvoorbeeld overeen met elke tekenreeks die bestaat uit het woord amount
plus een integraal nummer, gescheiden door een of meer niet-cijfers, zoals: amount=100
, amount is 3
, amount is equal to: 33
, enz.
Syntaxis
Directe reguliere expressies
re.match (patroon, string, vlag = 0) # Out: match patroon aan het begin van de string of Geen
re.search (patroon, string, vlag = 0) # Out: match patroon binnen string of Geen
re.findall (patroon, string, vlag = 0) # Out: lijst van alle overeenkomsten van patroon in string of []
re.finditer (patroon, string, vlag = 0) # Out: hetzelfde als re.findall, maar retourneert iteratorobject
re.sub (patroon, vervanging, string, vlag = 0) # Out: string met vervanging (string of functie) in plaats van patroon
Voorgecompileerde reguliere expressies
precompiled_pattern = re.compile (patroon, vlag = 0)
precompiled_pattern.match (string) # Out: match aan het begin van de string of Geen
precompiled_pattern.search (string) # Out: match overal in string of Geen
precompiled_pattern.findall (string) # Out: lijst van alle overeenkomende substrings
precompiled_pattern.sub (string / patroon / functie, string) # Out: vervangen string
Komt overeen met het begin van een string
Het eerste argument van re.match()
is de reguliere expressie, het tweede is de overeenkomende tekenreeks:
import re
pattern = r"123"
string = "123zzb"
re.match(pattern, string)
# Out: <_sre.SRE_Match object; span=(0, 3), match='123'>
match = re.match(pattern, string)
match.group()
# Out: '123'
Het is je misschien opgevallen dat de patroonvariabele een tekenreeks is die wordt voorafgegaan door r
, wat aangeeft dat de tekenreeks een onbewerkte tekenreeks is .
Een onbewerkte stringliter heeft een iets andere syntaxis dan een letterlijke string, namelijk een backslash \
in een onbewerkte stringliter betekent "slechts een backslash" en het is niet nodig om backlashes te verdubbelen om te ontsnappen aan "escape sequenties" zoals newlines ( \n
) , tabs ( \t
), backspaces ( \
), form-feeds ( \r
), enzovoort. In normale stringliterals moet elke backslash worden verdubbeld om te voorkomen dat deze wordt genomen als het begin van een escape-reeks.
Daarom is r"\n"
een reeks van 2 tekens: \
en n
. Regex-patronen gebruiken ook backslashes, bijv. \d
verwijst naar elk willekeurig cijfer. We kunnen voorkomen dat we dubbel moeten ontsnappen aan onze strings ( "\\d"
) door onbewerkte strings ( r"\d"
) te gebruiken.
Bijvoorbeeld:
string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't'
pattern = "\\t123" # this will match \t (escaping the backslash) followed by 123
re.match(pattern, string).group() # no match
re.match(pattern, "\t123zzb").group() # matches '\t123'
pattern = r"\\t123"
re.match(pattern, string).group() # matches '\\t123'
Het matchen vindt alleen vanaf het begin van de string plaats. Als je overal wilt matchen, gebruik dan re.search
:
match = re.match(r"(123)", "a123zzb")
match is None
# Out: True
match = re.search(r"(123)", "a123zzb")
match.group()
# Out: '123'
Zoeken
pattern = r"(your base)"
sentence = "All your base are belong to us."
match = re.search(pattern, sentence)
match.group(1)
# Out: 'your base'
match = re.search(r"(belong.*)", sentence)
match.group(1)
# Out: 'belong to us.'
Zoeken vindt overal in de string plaats, in tegenstelling tot re.match
. Je kunt ook re.findall
.
Je kunt ook zoeken aan het begin van de string (gebruik ^
),
match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'
match = re.search(r"^123", "a123zzb")
match is None
# Out: True
aan het einde van de string (gebruik $
),
match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'
match = re.search(r"123$", "123zzb")
match is None
# Out: True
of beide (gebruik zowel ^
als $
):
match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'
Groepering
Groeperen gebeurt tussen haakjes. Calling group()
retourneert een tekenreeks gevormd uit de overeenkomende haakjes subgroepen.
match.group() # Group without argument returns the entire match found
# Out: '123'
match.group(0) # Specifying 0 gives the same result as specifying no argument
# Out: '123'
Er kunnen ook argumenten worden gegeven aan group()
om een bepaalde subgroep op te halen.
Uit de documenten :
Als er een enkel argument is, is het resultaat een enkele string; als er meerdere argumenten zijn, is het resultaat een tuple met één item per argument.
Aanroepen van groups()
daarentegen, retourneert een lijst met tupels die de subgroepen bevatten.
sentence = "This is a phone number 672-123-456-9910"
pattern = r".*(phone).*?([\d-]+)"
match = re.match(pattern, sentence)
match.groups() # The entire match as a list of tuples of the paranthesized subgroups
# Out: ('phone', '672-123-456-9910')
m.group() # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(0) # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(1) # The first parenthesized subgroup.
# Out: 'phone'
m.group(2) # The second parenthesized subgroup.
# Out: '672-123-456-9910'
m.group(1, 2) # Multiple arguments give us a tuple.
# Out: ('phone', '672-123-456-9910')
Benoemde groepen
match = re.search(r'My name is (?P<name>[A-Za-z ]+)', 'My name is John Smith')
match.group('name')
# Out: 'John Smith'
match.group(1)
# Out: 'John Smith'
Hiermee maakt u een opnamegroep waarnaar zowel op naam als op index kan worden verwezen.
Niet-vastleggende groepen
Met (?:)
een groep gemaakt, maar de groep wordt niet vastgelegd. Dit betekent dat u het als een groep kunt gebruiken, maar het zal uw "groepsruimte" niet vervuilen.
re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')
re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')
Dit voorbeeld komt overeen met 11+22
of 11
, maar niet 11+
. Dit komt omdat het +
-teken en de tweede term gegroepeerd zijn. Aan de andere kant wordt het +
-teken niet vastgelegd.
Ontsnappen aan speciale tekens
Speciale tekens (zoals de karakterklasse haakjes [
en ]
hieronder) komen niet letterlijk overeen:
match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'
Door aan de speciale karakters te ontsnappen, kunnen ze letterlijk worden gematcht:
match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'
De functie re.escape()
kan hiervoor worden gebruikt:
re.escape('a[b]c')
# Out: 'a\\[b\\]c'
match = re.search(re.escape('a[b]c'), 'a[b]c')
match.group()
# Out: 'a[b]c'
De functie re.escape()
ontsnapt aan alle speciale tekens, dus het is handig als u een reguliere expressie samenstelt op basis van gebruikersinvoer:
username = 'A.C.' # suppose this came from the user
re.findall(r'Hi {}!'.format(username), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!', 'Hi ABCD!']
re.findall(r'Hi {}!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!']
Vervangen
Vervangingen kunnen op reeksen worden gemaakt met re.sub
.
Tekenreeksen vervangen
re.sub(r"t[0-9][0-9]", "foo", "my name t13 is t44 what t99 ever t44")
# Out: 'my name foo is foo what foo ever foo'
Groepsreferenties gebruiken
Vervangingen door een klein aantal groepen kunnen als volgt worden gemaakt:
re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Als u echter een groeps-ID zoals '10' maakt, werkt dit niet : \10
wordt gelezen als 'ID nummer 1 gevolgd door 0'. Je moet dus specifieker zijn en de \g<i>
-notatie gebruiken:
re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
Een vervangende functie gebruiken
items = ["zero", "one", "two"]
re.sub(r"a\[([0-3])\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]")
# Out: 'Items: zero, one, something, two'
Vind alle niet-overlappende overeenkomsten
re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']
Merk op dat de r
vóór "[0-9]{2,3}"
python vertelt om de string als zodanig te interpreteren; als een "ruwe" string.
Je kunt ook re.finditer()
die op dezelfde manier werkt als re.findall()
maar een iterator retourneert met SRE_Match
objecten in plaats van een lijst met tekenreeksen:
results = re.finditer(r"([0-9]{2,3})", "some 1 text 12 is 945 here 4445588899")
print(results)
# Out: <callable-iterator object at 0x105245890>
for result in results:
print(result.group(0))
''' Out:
12
945
444
558
889
'''
Voorgecompileerde patronen
import re
precompiled_pattern = re.compile(r"(\d+)")
matches = precompiled_pattern.search("The answer is 41!")
matches.group(1)
# Out: 41
matches = precompiled_pattern.search("Or was it 42?")
matches.group(1)
# Out: 42
Door een patroon samen te stellen, kan het later opnieuw worden gebruikt in een programma. Merk echter op dat Python recent gebruikte expressies in de cache opslaat ( docs , SO answer ), dus "programma's die slechts een paar reguliere expressies tegelijkertijd gebruiken, hoeven zich geen zorgen te maken over het compileren van reguliere expressies" .
import re
precompiled_pattern = re.compile(r"(.*\d+)")
matches = precompiled_pattern.match("The answer is 41!")
print(matches.group(1))
# Out: The answer is 41
matches = precompiled_pattern.match("Or was it 42?")
print(matches.group(1))
# Out: Or was it 42
Het kan worden gebruikt met re.match ().
Controleren op toegestane tekens
Als je wilt controleren of een string alleen een bepaalde set tekens bevat, in dit geval az, AZ en 0-9, kun je dit als volgt doen,
import re
def is_allowed(string):
characherRegex = re.compile(r'[^a-zA-Z0-9.]')
string = characherRegex.search(string)
return not bool(string)
print (is_allowed("abyzABYZ0099"))
# Out: 'True'
print (is_allowed("#*@#$%^"))
# Out: 'False'
U kunt ook de expressieregel aanpassen van [^a-zA-Z0-9.]
[^a-z0-9.]
, Om bijvoorbeeld hoofdletters niet toe te staan.
Gedeeltelijk tegoed: http://stackoverflow.com/a/1325265/2697955
Een tekenreeks splitsen met reguliere expressies
U kunt ook reguliere expressies gebruiken om een string te splitsen. Bijvoorbeeld,
import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']
vlaggen
Voor sommige speciale gevallen moeten we het gedrag van de reguliere expressie wijzigen, dit gebeurt met vlaggen. Vlaggen kan worden ingesteld op twee manieren, door middel van de flags
trefwoord of rechtstreeks in de expressie.
Vlaggen trefwoord
Hieronder een voorbeeld voor re.search
maar het werkt voor de meeste functies in de re
module.
m = re.search("b", "ABC")
m is None
# Out: True
m = re.search("b", "ABC", flags=re.IGNORECASE)
m.group()
# Out: 'B'
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE)
m is None
# Out: True
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL)
m.group()
# Out: 'A\nB'
Gemeenschappelijke vlaggen
Vlag | korte beschrijving |
---|---|
re.IGNORECASE , re.I | Laat het patroon de zaak negeren |
re.DOTALL , re.S | Maakt . match alles inclusief nieuwe lijnen |
re.MULTILINE , re.M | Zorgt ervoor dat ^ overeenkomt met het begin van een regel en $ het einde van een regel |
re.DEBUG | Schakelt foutopsporingsinformatie in |
Raadpleeg de documenten voor de volledige lijst van alle beschikbare vlaggen
Inline vlaggen
Uit de documenten :
(?iLmsux)
(Een of meer letters van de set 'i', 'L', 'm', 's', 'u', 'x'.)De groep komt overeen met de lege string; de letters stellen de overeenkomstige vlaggen in: re.I (hoofdletter negeren), re.L (locale afhankelijk), re.M (multi-line), re.S (punt komt overeen met alles), re.U (Unicode afhankelijk), en re.X (uitgebreid), voor de gehele reguliere expressie. Dit is handig als u de vlaggen wilt opnemen als onderdeel van de reguliere expressie, in plaats van een vlagargument door te geven aan de functie re.compile ().
Merk op dat de vlag (? X) verandert hoe de uitdrukking wordt geparseerd. Het moet eerst in de expressiereeks worden gebruikt, of na een of meer witruimte-tekens. Als er niet-witruimtetekens vóór de vlag staan, zijn de resultaten niet gedefinieerd.
Herhalen van wedstrijden met `re.finditer`
Je kunt re.finditer
om alle overeenkomsten in een string te herhalen. Dit geeft u (in vergelijking met re.findall
extra informatie, zoals informatie over de re.findall
in de string (indexen):
import re
text = 'You can try to find an ant in this string'
pattern = 'an?\w' # find 'an' either with or without a following word character
for match in re.finditer(pattern, text):
# Start index of match (integer)
sStart = match.start()
# Final index of match (integer)
sEnd = match.end()
# Complete match (string)
sGroup = match.group()
# Print match
print('Match "{}" found at: [{},{}]'.format(sGroup, sStart,sEnd))
Resultaat:
Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]
Pas een uitdrukking alleen op specifieke locaties aan
Vaak wilt u een uitdrukking alleen op specifieke plaatsen matchen (ze op andere plaatsen onaangeroerd laten). Overweeg de volgende zin:
An apple a day keeps the doctor away (I eat an apple everyday).
Hier komt de "appel" twee keer voor, die kan worden opgelost met zogenaamde backtracking-besturingswerkwoorden die worden ondersteund door de nieuwere regex
module. Het idee is:
forget_this | or this | and this as well | (but keep this)
Met ons appelvoorbeeld zou dit zijn:
import regex as re
string = "An apple a day keeps the doctor away (I eat an apple everyday)."
rx = re.compile(r'''
\([^()]*\) (*SKIP)(*FAIL) # match anything in parentheses and "throw it away"
| # or
apple # match an apple
''', re.VERBOSE)
apples = rx.findall(string)
print(apples)
# only one
Dit komt alleen overeen met "appel" wanneer het buiten de haakjes staat.
Dit is hoe het werkt:
- Kijkend van links naar rechts , verbruikt de regex-engine alles naar links, de
(*SKIP)
fungeert als een "altijd-ware-bewering". Nadien mislukt het correct op(*FAIL)
en backtracks. - Nu komt het op het punt van
(*SKIP)
van rechts naar links (oftewel tijdens het achteruitrijden) waar het verboden is verder naar links te gaan. In plaats daarvan wordt de motor opgedragen iets naar links weg te gooien en naar het punt te springen waar de(*SKIP)
is aangeroepen.