2.36. Csoportok és horgonyok

A minta többet is tehet annál, mint hogy kimondja: „ez a szöveg illeszkedik” – szét tudja szedni az illeszkedő darabokat, és név szerint át tudja adni mindegyiket az alkalmazásnak. A minta egy részét körülvevő zárójelek azt rögzítő csoporttá (capturing group) teszik; az illeszkedési objektum ekkor minden csoportot külön részszövegként tesz elérhetővé.

2.36.1. Rögzítő csoportok

A minta bármely részét tedd (...) zárójelek közé, hogy rögzítsd, amire illeszkedett:

>>> 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'
  • A 0. csoport mindig a teljes illeszkedés.

  • Az 1., 2., … csoportok a rögzített részszövegek, balról jobbra a nyitó zárójelük szerint sorszámozva.

  • Ha a match.group() metódust az utolsó csoporton túli indexszel hívod meg, IndexError keletkezik.

Gyakori minta a „illeszkedj egy ismert szerkezetre, és rögzítsd a változó részeket egészként”:

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. Nem rögzítő csoportok

A zárójelek egy részkifejezést is csoportosítanak, hogy egy kvantor az egész csoportra alkalmazható legyen. Az r'(ab)+' mintában a csoportosításnak ez az egyetlen célja – „egy vagy több ab„. Az, hogy az ab az 1. csoportként jelenik meg, mellékhatás.

Csoportosításhoz rögzítés nélkül használd a (?:...) formát:

>>> re.search(r'(?:ab)+', 'xababy').group(0)
'abab'

A nem rögzítő csoportok rendben tartják a csoportszámokat, amikor egy minta szerkezeti célból használ csoportosítást, de nem érdekli az egyes darabok kinyerése.

2.36.3. Horgonyok

A horgonyok nem egy karakterre illeszkednek – hanem egy pozícióra.

  • ^ – a szöveg eleje.

  • $ – a szöveg vége.

A horgonyok teszik eltérővé a re.match() és a re.search() viselkedését. Az re.match(p, s) ugyanaz, mint az re.search('^' + p, s): arra kényszeríti a mintát, hogy a 0. pozíciónál kezdődjön. A minta végéhez egy $ hozzáadása ezután azt eredményezi, hogy a minta a teljes szövegre illeszkedik és semmi másra:

>>> re.search(r'^\d+$', '12345')
<match num=1>
>>> re.search(r'^\d+$', '12345 ok') is None
True

A MicroPython re moduljában a ^ és a $ mindig a re.search() függvénynek átadott teljes szöveg elejét és végét jelenti. Nincs re.MULTILINE jelző, amely minden beágyazott sortörésnél illeszkedésre késztetné őket, és a $ nem illeszkedik egy záró \n előtti pozícióra sem – a bemenet abszolút végének kell lennie. Soronkénti viselkedéshez először bontsd fel a bemenetet sortörések mentén, és futtasd a mintát minden egyes soron.

2.36.4. Karakterhalmazok

A szögletes zárójelek karakterek explicit halmazát definiálják. Az illeszkedés pontosan egy karaktert fogyaszt el a halmazból.

  • [abc] – az a, b, c egyike.

  • [a-z] – egy karakter az a-z tartományban (a határokat is beleértve).

  • [a-zA-Z0-9] – betűk vagy számjegyek. Három tartomány kombinálva.

  • [^abc]nem az a, b, c egyike. A ^ csak akkor tagad, ha a zárójeleken belüli első karakter.

Példák:

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

Az első hívás a gyakorlatban None értéket ad vissza, mert a literális szöveg kisbetűs. A MicroPython re moduljának nincs re.IGNORECASE jelzője – a kis- és nagybetűt nem megkülönböztető illeszkedéshez írd be mindkét esetet a halmazba:

>>> re.search(r'[A-Fa-f0-9]{6}', 'colour #1a2b3c rest').group(0)
'1a2b3c'

Az osztály-rövidítések (\d, \s, \w és tagadott formáik) a [...] belsejében is használhatók: a [\w-] jelentése „szóalkotó karakterek vagy egy literális kötőjel”.

2.36.5. Mohó és lusta kvantorok

A *, +, ? és {m,n} kvantorok alapértelmezetten mohók – annyi karakterre illeszkednek, amennyit a minta többi része még megenged. Gyakran pontosan erre van szükség; néha viszont nem:

>>> re.search(r'<(.+)>', 'a <b> <c> d').group(1)
'b> <c'

A mohó .+ egészen az utolsó > jelig mindent megragadott. Egy ? hozzáfűzése a kvantort lustává teszi – a lehető legkevesebbre illeszkedik:

>>> re.search(r'<(.+?)>', 'a <b> <c> d').group(1)
'b'

A lusta forma az első > jelnél megáll. A lusta kvantorok állandóan előkerülnek, amikor kiegyensúlyozott elválasztók közötti tartalmat nyersz ki egy szövegből.

2.36.6. Visszahivatkozások a helyettesítésben

A re.sub() a helyettesítő szövegben a \1, \2, … formán keresztül visszahivatkozhat a rögzített csoportokra. A helyettesítés minden illeszkedést a rögzített darabok felhasználásával ír át:

>>> re.sub(r'(\d+)\.(\d+)', r'\2.\1', 'swap 12.34 and 5.6')
'swap 34.12 and 6.5'

Minden illeszkedés két számot rögzít, és a helyettesítés felcseréli őket. A \g<1> ugyanennek egy alternatív szintaxisa – akkor hasznos, ha a helyettesítésben a következő karakter egy számjegy (az r'\g<1>0' egy literális nullát fűz az 1. csoporthoz, ahelyett hogy a „10. csoportként” olvasná).

2.36.7. Mi nem áll rendelkezésre

Emlékeztető arról, mit nem támogat a MicroPython re modulja, arra az esetre, ha egy CPython-ból származó minta kerül ide, és meglep:

  • Előretekintés (?=...) és visszatekintés (?<=...) – nincs megvalósítva.

  • Nevesített csoportok (?P<name>...) és nevesített visszahivatkozások (?P=name) – nincs megvalósítva.

  • Olyan jelzőkonstansok, mint az re.IGNORECASE, re.MULTILINE, re.DOTALL – nincsenek figyelembe véve. A kis- és nagybetűt nem megkülönböztető halmazt magad építsd fel, vagy magad bontsd fel előre a bemenetet.

  • A match.groups(), match.span(), match.start() és match.end() metódusok olyan ROM-szinthez vannak kötve, amelyet egyetlen szállított OpenMV panel sem engedélyez. Az ezekre támaszkodó kód nem fog futni a kamerán.

A mintákkal, csoportokkal és horgonyokkal a kamerán elérhető regex-eszközkészlet elég kicsi ahhoz, hogy egy ülésben megtanulható legyen, és elég gazdag ahhoz, hogy a kontextusérzékeny elemzésen kívül mindent megoldjon.