2.36. Skupiny a kotvy¶
Vzor umí víc než jen říct „tento řetězec odpovídá“ – dokáže rozebrat odpovídající části a každou z nich předat aplikaci pod jménem. Závorky kolem části vzoru z ní udělají zachytávací skupinu (capturing group); objekt shody pak každou skupinu zpřístupní jako samostatný podřetězec.
2.36.1. Zachytávací skupiny¶
Obalením libovolné části vzoru do (...) zachytíte to, čemu odpovídala:
>>> 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'
Skupina 0 je vždy celá shoda.
Skupiny 1, 2, … jsou zachycené podřetězce, číslované zleva doprava podle jejich otevírací závorky.
Volání
match.group()s indexem za poslední skupinou vyvoláIndexError.
Běžným postupem je „najít známou strukturu a proměnlivé části zachytit jako celá čísla“:
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. Nezachytávací skupiny¶
Závorky také seskupují dílčí výraz, aby se kvantifikátor mohl vztahovat na celou skupinu. To je jediný účel seskupení v r'(ab)+' – „jeden nebo více výskytů ab“. Skutečnost, že se ab objeví jako skupina 1, je vedlejší efekt.
Pro seskupení bez zachytávání použijte (?:...)
>>> re.search(r'(?:ab)+', 'xababy').group(0)
'abab'
Nezachytávací skupiny udržují čísla skupin přehledná, když vzor používá seskupení kvůli struktuře, ale nezajímá ho vytahování jednotlivých částí.
2.36.3. Kotvy¶
Kotvy neodpovídají žádnému znaku – odpovídají pozici.
^– začátek řetězce.$– konec řetězce.
Kotvy způsobují, že se re.match() a re.search() chovají rozdílně. re.match(p, s) je totéž co re.search('^' + p, s): vynutí, aby vzor začínal na pozici 0. Přidání $ na konec vzoru pak způsobí, že vzor odpovídá celému řetězci a ničemu jinému:
>>> re.search(r'^\d+$', '12345')
<match num=1>
>>> re.search(r'^\d+$', '12345 ok') is None
True
^ a $ v MicroPython re vždy znamenají začátek a konec celého řetězce předaného do re.search(). Neexistuje žádný příznak re.MULTILINE, který by je nutil odpovídat na každém vnořeném zalomení řádku, a $ neodpovídá ani pozici před koncovým \n – musí to být úplný konec vstupu. Pro chování po jednotlivých řádcích nejprve rozdělte vstup podle zalomení řádků a spusťte vzor na každém řádku.
2.36.4. Znakové množiny¶
Hranaté závorky definují explicitní množinu znaků. Shoda spotřebuje přesně jeden znak z této množiny.
[abc]– jeden ze znakůa,b,c.[a-z]– jeden znak v rozsahua-z(včetně).[a-zA-Z0-9]– písmena nebo číslice. Tři rozsahy spojené dohromady.[^abc]– žádný ze znakůa,b,c.^neguje pouze tehdy, je-li prvním znakem uvnitř závorek.
Příklady:
>>> 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
První volání v praxi vrátí None, protože doslovný text je psaný malými písmeny. MicroPython re nemá žádný příznak re.IGNORECASE – pro shodu bez ohledu na velikost písmen zapište do množiny obě varianty:
>>> re.search(r'[A-Fa-f0-9]{6}', 'colour #1a2b3c rest').group(0)
'1a2b3c'
Zkratky tříd (\d, \s, \w a jejich negované formy) lze používat i uvnitř [...]: [\w-] znamená „slovní znaky nebo doslovná pomlčka“.
2.36.5. Hltavé vs. líné kvantifikátory¶
Kvantifikátory *, +, ? a {m,n} jsou ve výchozím stavu hltavé (greedy) – odpovídají tolika znakům, kolik jen zbytek vzoru ještě dovolí. Často je to přesně to, co chceme; někdy ale ne:
>>> re.search(r'<(.+)>', 'a <b> <c> d').group(1)
'b> <c'
Hltavé .+ pohltilo vše až k poslednímu >. Připojení ? udělá z kvantifikátoru líný (lazy) – odpovídá co nejméně:
>>> re.search(r'<(.+?)>', 'a <b> <c> d').group(1)
'b'
Líná forma se zastaví u prvního >. Líné kvantifikátory přicházejí na řadu neustále při vytahování vyvážených oddělovačů z řetězce.
2.36.6. Zpětné odkazy v náhradě¶
re.sub() se může v náhradním řetězci odkazovat zpět na zachycené skupiny pomocí \1, \2, … Náhrada přepíše každou shodu s využitím zachycených částí:
>>> re.sub(r'(\d+)\.(\d+)', r'\2.\1', 'swap 12.34 and 5.6')
'swap 34.12 and 6.5'
Každá shoda zachytí dvě čísla a náhrada je prohodí. \g<1> je alternativní syntaxe pro totéž – užitečná, když je dalším znakem v náhradě číslice (r'\g<1>0' připojí doslovnou nulu ke skupině 1, místo aby se to četlo jako „skupina 10“).
2.36.7. Co není k dispozici¶
Připomenutí toho, co MicroPython re nepodporuje, pro případ, že by sem zabloudil vzor z CPythonu a překvapil vás:
Lookahead
(?=...)a lookbehind(?<=...)– nejsou implementovány.Pojmenované skupiny
(?P<name>...)a pojmenované zpětné odkazy(?P=name)– nejsou implementovány.Příznakové konstanty jako
re.IGNORECASE,re.MULTILINE,re.DOTALL– nejsou respektovány. Sestavte si množinu necitlivou na velikost písmen nebo si vstup rozdělte sami předem.Metody
match.groups(),match.span(),match.start()amatch.end()jsou podmíněny úrovní ROM, kterou žádná dodávaná deska OpenMV nepovoluje. Kód, který se na ně spoléhá, na kameře nepoběží.
Se vzory, skupinami a kotvami je sada nástrojů pro regulární výrazy na kameře dostatečně malá na to, aby se dala naučit za jedno posezení, a zároveň dostatečně bohatá, aby zvládla vše kromě kontextově citlivého parsování.