2.36. Ryhmät ja ankkurit#
Säännöllinen lauseke voi tehdä muutakin kuin todeta, että ”tämä merkkijono täsmää” – se voi erottaa täsmänneet osat toisistaan ja luovuttaa kunkin sovellukselle nimellä. Sulkeet kuvion osan ympärillä tekevät siitä kaappaavan ryhmän; täsmäysolio paljastaa tämän jälkeen jokaisen ryhmän erillisenä alimerkkijonona.
2.36.1. Kaappaavat ryhmät#
Ympäröi mikä tahansa kuvion osa merkeillä (...) kaapataksesi sen, mihin se täsmäsi:
>>> import re
>>> m = re.search(r'temp (\d+) at (\d+)s', 'temp 42 at 137s ok')
>>> m.group(0)
'temp 42 at 137s'
>>> m.group(1)
'42'
>>> m.group(2)
'137'
Ryhmä 0 on aina koko täsmäys.
Ryhmät 1, 2, … ovat kaapatut alimerkkijonot, numeroituina vasemmalta oikealle niiden avaavan sulkeen mukaan.
Metodin
match.group()kutsuminen indeksillä, joka ylittää viimeisen ryhmän, nostaa virheenIndexError.
Yleinen kuvio on ”täsmää tunnettuun rakenteeseen, kaappaa muuttuvat osat kokonaislukuina”:
def parse_temp(line):
m = re.search(r'temp (\d+) at (\d+)s', line)
if not m:
return None
return int(m.group(1)), int(m.group(2))
2.36.2. Kaappaamattomat ryhmät#
Sulkeet myös ryhmittelevät alilausekkeen niin, että määrällistäjä voi koskea koko ryhmää. Tämä on ryhmittelyn ainoa tarkoitus kuviossa r'(ab)+' – ”yksi tai useampi ab”. Se, että ab esiintyy ryhmänä 1, on sivuvaikutus.
Ryhmitelläksesi ilman kaappaamista käytä muotoa (?:...)
>>> re.search(r'(?:ab)+', 'xababy').group(0)
'abab'
Kaappaamattomat ryhmät pitävät ryhmänumeroinnin siistinä, kun kuvio käyttää ryhmittelyä rakenteen vuoksi mutta ei välitä kunkin osan poimimisesta.
2.36.3. Ankkurit#
Ankkurit eivät täsmää merkkiin – ne täsmäävät sijaintiin.
^– merkkijonon alku.$– merkkijonon loppu.
Ankkurit ovat se, mikä saa funktiot re.match() ja re.search() käyttäytymään eri tavoin. re.match(p, s) on sama kuin re.search('^' + p, s): se pakottaa kuvion alkamaan sijainnista 0. Kun kuvion loppuun lisätään $, kuvio täsmää tällöin koko merkkijonoon eikä mihinkään muuhun:
>>> re.search(r'^\d+$', '12345')
<match num=1>
>>> re.search(r'^\d+$', '12345 ok') is None
True
MicroPythonin re -moduulissa ^ ja $ tarkoittavat aina sen koko merkkijonon alkua ja loppua, joka välitetään funktiolle re.search(). Ei ole olemassa re.MULTILINE -lippua, joka saisi ne täsmäämään jokaisen upotetun rivinvaihdon kohdalla, eikä $ täsmää lopettavaa \n-merkkiä edeltävään sijaintiinkaan – sen on oltava syötteen ehdoton loppu. Saadaksesi rivikohtaisen toiminnan jaa syöte ensin rivinvaihtojen kohdalta ja aja kuvio kullekin riville.
2.36.4. Merkkijoukot#
Hakasulkeet määrittelevät eksplisiittisen merkkijoukon. Täsmäys kuluttaa täsmälleen yhden merkin joukosta.
[abc]– yksi merkeistäa,b,c.[a-z]– yksi merkki väliltäa-z(ääripäät mukaan luettuina).[a-zA-Z0-9]– kirjaimia tai numeroita. Kolme väliä yhdistettynä.[^abc]– ei mikään merkeistäa,b,c. Merkki^kieltää vain silloin, kun se on hakasulkeiden ensimmäinen merkki.
Esimerkkejä:
>>> re.search(r'[A-F0-9]{6}', 'colour #1a2b3c rest').group(0)
'1A2B3C'
>>> re.search(r'[A-F0-9]{6}', 'colour #1a2b3c rest') is None
True
Ensimmäinen kutsu palauttaa käytännössä None, koska literaaliteksti on pienaakkosin. MicroPythonin re -moduulissa ei ole re.IGNORECASE -lippua – täsmätäksesi kirjainkoosta riippumatta kirjoita molemmat kirjainkoot joukkoon:
>>> re.search(r'[A-Fa-f0-9]{6}', 'colour #1a2b3c rest').group(0)
'1a2b3c'
Luokkien lyhennyksiä (\d, \s, \w ja niiden kielletyt muodot) voi käyttää myös merkinnän [...] sisällä: [\w-] tarkoittaa ”sanamerkkejä tai literaaliviivaa”.
2.36.5. Ahneet ja laiskat määrällistäjät#
Määrällistäjät *, +, ? ja {m,n} ovat oletuksena ahneita – ne täsmäävät niin moneen merkkiin kuin loput kuviosta vielä sallivat. Usein juuri sitä halutaan; toisinaan ei:
>>> re.search(r'<(.+)>', 'a <b> <c> d').group(1)
'b> <c'
Ahne .+ nappasi mukaansa kaiken aina viimeiseen merkkiin > saakka. Merkin ? lisääminen tekee määrällistäjästä laiskan – se täsmää niin vähään kuin mahdollista:
>>> re.search(r'<(.+?)>', 'a <b> <c> d').group(1)
'b'
Laiska muoto pysähtyy ensimmäiseen merkkiin >. Laiskoja määrällistäjiä tarvitaan jatkuvasti, kun merkkijonosta poimitaan tasapainotettuja erottimia.
2.36.6. Takaisinviittaukset korvauksessa#
Funktio re.sub() voi viitata takaisin kaapattuihin ryhmiin korvausmerkkijonossa merkinnöillä \1, \2, … Korvaus kirjoittaa jokaisen täsmäyksen uudelleen kaapattujen osien avulla:
>>> re.sub(r'(\d+)\.(\d+)', r'\2.\1', 'swap 12.34 and 5.6')
'swap 34.12 and 6.5'
Jokainen täsmäys kaappaa kaksi numeroa, ja korvaus vaihtaa niiden paikkaa. \g<1> on vaihtoehtoinen syntaksi samalle asialle – hyödyllinen, kun korvauksen seuraava merkki on numero (r'\g<1>0' lisää literaalinollan ryhmän 1 perään sen sijaan, että lukisi ”ryhmä 10”).
2.36.7. Mitä ei ole käytettävissä#
Muistutus siitä, mitä MicroPythonin re ei tue, siltä varalta että CPythonista peräisin oleva kuvio päätyy tänne ja yllättää sinut:
Eteenpäinkatselu
(?=...)ja taaksepäinkatselu(?<=...)– ei toteutettu.Nimetyt ryhmät
(?P<name>...)ja nimetyt takaisinviittaukset(?P=name)– ei toteutettu.Lippuvakiot kuten
re.IGNORECASE,re.MULTILINE,re.DOTALL– ei huomioida. Rakenna kirjainkoosta riippumaton joukko tai esijaa syöte itse.Metodit
match.groups(),match.span(),match.start()jamatch.end()on portitettu ROM-tasolle, jota mikään toimitettu OpenMV-kortti ei ota käyttöön. Niihin nojaava koodi ei toimi kamerassa.
Kuvioiden, ryhmien ja ankkureiden ansiosta kameran regex-työkalupakki on tarpeeksi pieni opittavaksi yhdeltä istumalta ja tarpeeksi rikas tekemään kaiken kontekstiriippuvaista jäsennystä lukuun ottamatta.