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.