2.35. A minták alapjai¶
A reguláris kifejezés egy kis nyelv, amellyel a szövegeket a pontos tartalmuk helyett a formájuk alapján írhatjuk le. Akkor használd, ha egy szöveg akkor és csak akkor illeszkedik, ha követ egy olyan mintát, amelyet le tudsz írni, de nem tudsz felsorolni – „számjegyek sorozata, amelyet egy mértékegység követ”, „egy sor, amely ERROR szóval kezdődik és egy számmal végződik”, „ezen fájlkiterjesztések bármelyike, tetszőleges sorrendben, opcionális v előtagokkal”.
A re modulhoz csak akkor nyúlj, ha egy egyszerű szöveges metódus nem elég.
str.startswith(),str.endswith()– rögzített előtag vagy utótag tesztelése.in– annak tesztelése, hogy egy rögzített részszöveg jelen van-e.str.split(),str.find(),str.replace()– rögzített elválasztókkal való munka.
Mindegyik gyorsabb, könnyebben olvasható és nehezebb elrontani, mint a megfelelő regex. A regexet akkor használd, ha a szöveg formája számít, a pontos részszöveg pedig nem.
2.35.1. A négy dolog, amit használni fogsz¶
A MicroPython re modulja négy dolgot tesz elérhetővé:
re.compile()– egy mintaszöveget újrahasználható, lefordított mintaobjektummá alakít.re.match()– megpróbálja a mintát egy szöveg elején. A minta a 0. pozícióhoz van horgonyozva.re.search()– megpróbálja a mintát egy szöveg bármely részén. Az első illeszkedést adja vissza.re.sub()– megkeres minden illeszkedést és lecseréli.
Jelentős hiányosságok a CPython-hoz képest: nincs re.findall, nincs re.finditer, nincs modulszintű re.split (a lefordított mintáknak van helyette split metódusuk), nincs re.fullmatch, és nincsenek jelzőkonstansok, mint az re.IGNORECASE. Ahol a CPython-on ezek egyikéhez nyúlnál, ott építsd fel a megfelelőjét a re.search() ciklusban való használatával.
2.35.2. Egy első minta¶
Az r'\d+' minta egy vagy több számjegyre illeszkedik:
>>> import re
>>> m = re.search(r'\d+', 'sensor reading 42 ok')
>>> m.group(0)
'42'
Néhány észrevennivaló:
A minta nyers szövegként (
r'...') van megírva, hogy a\dvisszaperjele aremodulhoz jusson el, ahelyett hogy Python szövegfeloldó szekvenciaként dolgoznák fel. Regex mintákhoz mindig használj nyers szövegeket.A
re.search()siker esetén egy illeszkedési objektumot, kudarc eseténNoneértéket ad vissza. Amatch.group()hívása előtt mindig ellenőrizd.Az
m.group(0)a teljes szöveg, amelyre a minta illeszkedett. Az 1., 2., … csoport később jelenik meg, ha a minta rögzítő zárójeleket tartalmaz.
Ugyanez a minta a re.match() függvénnyel None értéket ad vissza, mert a szöveg nem kezdődik számjeggyel:
>>> re.match(r'\d+', 'sensor reading 42 ok') is None
True
>>> re.match(r'\d+', '42 readings')
<match num=1>
2.35.3. A minta részei¶
A leghasznosabb minták egy kis elemkészletből épülnek fel. Azok, amelyek a MicroPythonban működnek:
Literális karakterek – minden olyan karakter, amely nem speciális, önmagára illeszkedik. A hello a hello szövegre illeszkedik.
Speciális karakterek – a . ^ $ * + ? { } [ ] \ | ( ) karaktereknek mind az alábbi jelentésük van. Ha egyiküket literálisan szeretnéd illeszteni, escape-eld egy visszaperjellel: a \. egy literális pontra illeszkedik.
Karakterosztályok – gyakori karakterhalmazok rövidítései:
\d– bármely0-9számjegy\D– bármely nem számjegy\s– bármely whitespace karakter (szóköz, tabulátor, sortörés)\S– bármely nem whitespace karakter\w– bármely „szóalkotó” karakter: betűk, számjegyek, aláhúzás\W– bármely nem szóalkotó karakter.– bármely karakter a sortörés kivételével
Kvantorok – hányszor kell az előző elemnek illeszkednie:
*– nulla vagy több (mohó)+– egy vagy több (mohó)?– nulla vagy egy{n}– pontosan n{m,n}– m és n között (a határokat is beleértve)
Kombinálás: a \d{3}-\d{4} három számjegyre, egy kötőjelre, négy számjegyre illeszkedik. A \s+ egy vagy több whitespace karakterre illeszkedik. A hello.*world a hello szövegre, bármire (akár semmire is), majd a world szövegre illeszkedik.
Megjegyzés
A mohó azt jelenti, hogy a kvantor annyit fogyaszt el a bemenetből, amennyit csak tud, miközben a minta többi része még illeszkedhet. A hello x world y world ellen a hello.*world mintában lévő .* a leghosszabb olyan szakaszra illeszkedik, amely még meghagy egy world szót a végén – az x world y szöveget rögzíti, nem pedig a rövidebb x szöveget. Ugyanez igaz a + jelre és a {m,n} tartományformára is: a motor a lehető leghosszabb illeszkedést veszi, majd csak akkor lép vissza, ha a minta többi része kudarcot vall.
2.35.4. Helyettesítés¶
A re.sub() megkeres minden illeszkedést, és lecseréli egy szövegre. A helyettesítés a \1, \2, … formán keresztül hivatkozhat a rögzített csoportokra (ezzel a csoportszintaxis többi részével együtt később foglalkozunk). Csoportok nélkül az re.sub egy egyszerű keresés-és-csere egy regexen:
>>> re.sub(r'\s+', ' ', 'too many spaces')
'too many spaces'
>>> re.sub(r'\d+', 'N', 'log 12, log 345, log 6')
'log N, log N, log N'
A harmadik argumentum az a szöveg, amelyen dolgozni kell; az eredmény egy új szöveg, amelyben minden illeszkedés le van cserélve.
2.35.5. Felbontás – csak lefordított mintán¶
Modulszinten nincs re.split. Egy regex mentén való felbontáshoz először fordítsd le a mintát, és hívd meg a split metódusát:
>>> sep = re.compile(r'\s*,\s*')
>>> sep.split('a , b,c , d')
['a', 'b', 'c', 'd']
Az opcionális második argumentum korlátozza a felbontások számát:
>>> sep.split('a, b, c, d', 2)
['a', 'b', 'c, d']
2.35.6. Fordítás újrahasználatra¶
Ha ugyanaz a minta sokszor fut le – egy cikluson belül vagy egy gyakran hívott függvényben –, fordítsd le egyszer, és használd újra a lefordított objektumot:
digit_run = re.compile(r'\d+')
def first_number(line):
m = digit_run.search(line)
return int(m.group(0)) if m else None
A pattern.match() és a pattern.search() meghívása egy lefordított objektumon ugyanaz, mint a modulszintű függvények, de minden híváskor megspórolja az újrafordítás költségét.
2.35.7. Minták, amelyek semmire sem illeszkednek¶
Különösen három minta szokta zavarba ejteni a fejlesztőket:
A
.*az üres szövegre illeszkedik. Azre.search(r'.*', s).group(0)bármilyen bemenetre''értéket ad vissza.Egy nem escape-elt speciális karaktert tartalmazó minta szintaktikai hiba. Az
re.compile(r'cost: $5')ValueErrorhibát vált ki, mert a$jelentése „a szöveg vége”. Használd azr'cost: \$5'formát.A pont
.nem illeszkedik a sortörésre. Több soron átívelő illeszkedéshez írd meg a mintát úgy, hogy azokat explicit módon kezelje a[\s\S]segítségével, vagy egyszerre egy sort adj át.
Ezekkel az elemekkel egy minta szinte bármilyen rögzített formájú szövegrészletre illeszkedhet. A strukturált adatok visszanyerése az illeszkedésből rögzítő csoportokat igényel.