Säännölliset lausekkeet
Python on mainio työkalu tekstin käsittelemiseen. Yksi työkalu tekstin käsittelemisessä ovat säännölliset lausekkeet (regular expressions), joiden avulla voi esimerkiksi poimia ja etsiä merkkijonoja, jotka ovat tietyn muotoisia. Tässä osiossa käydään läpi säännöllisten lausekkeiden perusteita, ja löydät lisää tietoa Pythonin omasta tutoriaalista.
Mitä ovat säännölliset lausekkeet?
Säännölliset lausekkeet ovat tavallaan ohjelmointikieli ohjelmointikielen sisällä. Lausekkeilla on oma syntaksinsa, jonka mukaan ne määritellään. Ideana on, että säännöllisellä lausekkeella määritellään sellaisten merkkijonojen joukko, jotka ovat tiettyjen sääntöjen mukaisia.
Tarkistellaan yksinkertaista esimerkkiä lausekkeiden käytöstä ennen tarkempaa perehtymistä sääntöihin:
import re
sanat = ["Python", "Ponneton", "Ponttooni", "Pullero", "Pallon"]
for sana in sanat:
# merkkijonon tulee alkaa "P" ja päättyä "on"
if re.search("^P.*on$", sana):
print(sana, "löytyy!")
Python löytyy! Ponneton löytyy! Pallon löytyy!
Pythonissa säännöllisiä lausekkeita voi käsitellä moduulin re
avulla. Esimerkiksi yllä olevassa koodissa oleva metodi search
etsii merkkijonosta osaa, joka täsmää annettuun säännölliseen lausekkeeseen.
Huomaa, että säännöllinen lauseke annetaan merkkijonona funktion search
parametriksi.
Toinen esimerkki etsii merkkijonosta luvut. Metodi findall
palauttaa kaikki säännölliseen lausekkeeseen täsmäävät osajonot listana:
import re
lause = "Eka, 2 !#kolmas 44 viisi 678xyz962"
luvut = re.findall("\d+", lause)
for luku in luvut:
print(luku)
2 44 678 962
Säännöllisten lausekkeiden syntaksi
Tarkastellaan seuraavaksi syntaksia, jota säännöllisissä lausekkeissa käytetään. Useimmissa esimerkeissä käytetään samaa testiohjelmaa eri syötteillä.
import re
lauseke = input("Anna lauseke: ")
while True:
mjono = input("Anna merkkijono: ")
if mjono == "":
break
if re.search(lauseke, mjono):
print("Osuma!")
else:
print("Ei osumaa.")
Vaihtoehtoiset alijonot
Pystyviivalla voidaan erottaa vaihtoehtoisia osajonoja. Esimerkiksi lauseke 911|112
täsmää merkkijonoihin, joista löytyy joko osajono 911
tai osajono 112
.
Esimerkiksi
Anna lauseke: aa|ee|ii Anna testijono: saapas Osuma! Anna testijono: teema Osuma! Anna testijono: iilimato Osuma! Anna testijono: ooppera Ei osumaa. Anna testijono: uuttera Ei osumaa.
Merkkijoukot
Hakasulkeiden väliin voidaan merkitä joukko hyväksyttyjä merkkejä. Esimerkiksi merkintä [aeio]
täsmää jonoihin, joista löytyy jokin merkeistä a, e, i, tai o. Merkintätapa sallii myös väliviivan käytön. Merkintä [0-68a-d]
hyväksyy jonot, joista löytyy numero nollasta kuuteen, kahdeksikko tai merkki väliltä a...d. Merkintä [1-3][0-9]
hyväksyy kaksinumeroiset luvut väliltä 10...39.
Esimerkiksi:
Anna lauseke: [C-FRSÖ] Anna testijono: C Osuma! Anna testijono: E Osuma! Anna testijono: G Ei osumaa. Anna testijono: R Osuma! Anna testijono: Ö Osuma! Anna testijono: T Ei osumaa.
Toistaminen
Lausekkeen osaa voidaan toistaa esimerkiksi seuraavien operaattorien avulla:
*
toistaa osaa minkä tahansa määrän kertoja (myös nolla)+
toistaa osaa minkä tahansa määrän kertoja (ainakin yhden){m}
toistaa osaa täsmälleenm
kertaa
Operaattorit viittaavat niitä edeltävään lausekkeen osaan. Esimerkiksi lauseke ba+b
hyväksyy esimerkiksi osajonot bab
, baab
ja baaaaaaaaaaab
. Lauseke A[BCDE]*Z
puolestaan hyväksyy esimerkiksi osajonot AZ
, ADZ
tai ABCDEBCDEBCDEZ
.
Esimerkiksi:
Anna lauseke: 1[234]*5 Anna testijono: 15 Osuma! Anna testijono: 125 Osuma! Anna testijono: 145 Osuma! Anna testijono: 12342345 Osuma! Anna testijono: 126 Ei osumaa. Anna testijono: 165 Ei osumaa.
Muita erikoismerkkejä
Pisteellä merkitään mitä tahansa yksittäistä merkkiä. Niinpä merkintä c...o
vastaa esimerkiksi merkkijonoja c-3po
tai combo
. Merkillä ^
voidaan määritellä, että osuman pitää löytyä merkkijonon alusta, ja vastaavasti merkillä $
, että sen on oltava lopussa. Näillä voidaan näppärästi myös rajata sääntö koskemaan vain annettuja merkkejä:
Anna lauseke: ^[123]*$ Anna testijono: 4 Ei osumaa. Anna testijono: 1221 Osuma! Anna testijono: 333333333 Osuma!
Kenoviivaa voidaan käyttää etsimään erikoismerkkejä. Merkintä 1+
tarkoittaa yhtä tai useampaa ykköstä, mutta merkintä 1\+
merkkijonoa 1+
.
Esimerkiksi
Anna lauseke: ^\* Anna testijono: moi* Ei osumaa. Anna testijono: m*o*i Ei osumaa. Anna testijono: *moi Osuma!
Kaarisulkeilla voidaan ryhmitellä lausekkeen osia. Esimerkiksi lauseke (ab)+c
hyväksyy jonot abc
, ababc
ja ababababababc
, mutta ei esimerkiksi jonoja ac
tai bc
.
Esimerkiksi
Anna lauseke: ^(jabba).*(hut)$ Anna testijono: jabba the hut Osuma! Anna testijono: jabba a hut Osuma! Anna testijono: jarmo the hut Ei osumaa. Anna testijono: jabba the smut Ei osumaa.
Säännölliset lausekkeet
/
Harjoitellaan hieman säännöllisten lausekkeiden käyttöä.
Viikonpäivät
Tee säännöllisen lausekkeen avulla funktio on_viikonpaiva(merkkijono: str)
joka palauttaa True
, jos sen parametrina saama merkkijono sisältää viikonpäivän lyhenteen (ma, ti, ke, to, pe, la tai su).
Esimerkki funktion kutsumisesta:
print(on_viikonpaiva("ma"))
print(on_viikonpaiva("pe"))
print(on_viikonpaiva("tu"))
True True False
Vokaalitarkistus
Tee funktio kaikki_vokaaleja(merkkijono: str)
, joka tarkistaa säännöllisen lausekkeen avulla, ovatko parametrina annetun merkkijonon kaikki merkit vokaaleja.
Esimerkki funktion kutsumisesta:
print(kaikki_vokaaleja("eioueioieoieouyyyy"))
print(kaikki_vokaaleja("autoooo"))
True False
Kellonaika
Tee funktio kellonaika(merkkijono: str)
, joka tarkistaa säännöllisen lausekkeen avulla, onko parametrina oleva merkkijono muotoa tt:mm:ss
oleva kellonaika (tunnit, minuutit ja sekunnit kaksinumeroisina).
Esimerkki funktion kutsumisesta:
print(kellonaika("12:43:01"))
print(kellonaika("AB:01:CD"))
print(kellonaika("17:59:59"))
print(kellonaika("33:66:77"))
True False True False
Loppuhuipennus
Harjoitellaan vielä osan lopussa hieman laajemman ohjelman tekemistä olioita hyödyntäen. Tämä tehtävä ei sijainnistaan huolimatta liity mitenkään säännöllisiin lausekkeisiin, mutta luvun Funktio parametrina asia tulee olemaan tarpeen ja myös listakoosteet voivat olla käyttökelpoisia.
Sovelluksen rakenteelle voi ottaa inspiraatiota osan 10 viimeisestä luvusta.
Tilastot ojennukseen
/
Tässä tehtävässä tehdään sovellus, jonka avulla on mahdollista tarkastella NHL-jääkiekkoliigan tilastoja muutamassa hieman erilaisessa muodossa.
Tehtäväpohjan mukana tulee kaksi json-muodossa olevaa tiedostoa osa.json
ja kaikki.json
, näistä ensimmäinen on tarkoitettu lähinnä testailun avuksi. Jälkimmäinen sisältää kaikkien kaudella 2019-20 pelanneiden pelaajien statistiikat.
Yksittäisen pelaajan tiedot ovat muodossa
{
"name": "Patrik Laine",
"nationality": "FIN",
"assists": 35,
"goals": 28,
"penalties": 22,
"team": "WPG",
"games": 68
},
ja molemmat tiedostoista sisältävät yksittäisten pelaajien tiedot taulukossa.
Jos et muista, miten json-muotoinen tiedosto saadaan luettua Python-ohjelmaan, voit kerrata tämän osan 7 materiaalista.
Tee nyt ohjelma, joka kysyy aluksi tiedoston nimeä ja tarjoaa sitten seuraavat toiminnot:
- yksittäisen pelaajan tietojen haku nimen perusteella
- listaus joukkueiden nimien lyhenteistä (aakkosjärjestyksessä)
- listaus maiden nimien lyhenteistä (aakkosjärjestyksessä)
Näistä toiminnoista saa yhden pisteen. Ohjelman tulee toimia seuraavasti:
tiedosto: osa.json luettiin 14 pelaajan tiedot
komennot: 0 lopeta 1 hae pelaaja 2 joukkueet 3 maat 4 joukkueen pelaajat 5 maan pelaajat 6 eniten pisteitä 7 eniten maaleja
komento: 1 nimi: Travis Zajac
Travis Zajac NJD 9 + 16 = 25
komento: 2 BUF CGY DAL NJD NYI OTT PIT WPG WSH
komento: 3 CAN CHE CZE SWE USA
komento: 0
Huomaa, että pelaajien tulostusasun pitää olla täsmälleen seuraavanlainen:
Leon Draisaitl EDM 43 + 67 = 110 Connor McDavid EDM 34 + 63 = 97 Travis Zajac NJD 9 + 16 = 25 Mike Green EDM 3 + 8 = 11 Markus Granlund EDM 3 + 1 = 4 123456789012345678901234567890123456789
Alimman rivin numerot on lisätty helpottamaan oikean merkkimäärän laskemista. Joukkueen nimen lyhenne siis tulostetaan alkaen rivin 22. merkistä. Plus on rivin 30. merkki ja = rivin 35. merkki. Kaikki luvut tulee tasata oikeaan reunaan omaa tulostusaluettaan. Tyhjät kohdat ovat välilyöntejä.
Tulostuksen muotoilu kannattaa hoitaa f-merkkijonoina samaan tapaan kuin tässä osan 6 tehtävässä.
Seuraavat toiminnot tuovat toisen pisteen:
- joukkueen pelaajien listaaminen pisteiden (joka saadaan laskemalla goals + assits) mukaisessa järjestyksessä
- tietyn maan pelaajien listaaminen pisteiden mukaisessa järjestyksessä
Toiminnallisuus on seuraava:
tiedosto: osa.json luettiin 14 pelaajan tiedot
komennot: 0 lopeta 1 hae pelaaja 2 joukkueet 3 maat 4 joukkueen pelaajat 5 maan pelaajat 6 eniten pisteitä 7 eniten maaleja
komento: 4 joukkue: OTT
Drake Batherson OTT 3 + 7 = 10 Jonathan Davidsson OTT 0 + 1 = 1
komento: 5 maa: CAN
Jared McCann PIT 14 + 21 = 35 Travis Zajac NJD 9 + 16 = 25 Taylor Fedun DAL 2 + 7 = 9 Mark Jankowski CGY 5 + 2 = 7 Logan Shaw WPG 3 + 2 = 5
komento: 0
Kolmannen pisteen saa seuraavilla toiminnoilla:
- n eniten pistettä saanutta pelaajaa
- jos kahden pelaajan pistemäärä on sama, ratkaisee maalimäärä
- n eniten maaleja (goals) tehnyttä pelaajaa
- jos kahden pelaajan maalimäärä on sama, järjestyksen ratkaisee se kummalla on vähemmän otteluja (games)
Toiminnallisuus on seuraava:
tiedosto: osa.json luettiin 14 pelaajan tiedot
komennot: 0 lopeta 1 hae pelaaja 2 joukkueet 3 maat 4 joukkueen pelaajat 5 maan pelaajat 6 eniten pisteitä 7 eniten maaleja
komento: 6 kuinka monta: 2
Jakub Vrana WSH 25 + 27 = 52 Jared McCann PIT 14 + 21 = 35
komento: 6 kuinka monta: 5
Jakub Vrana WSH 25 + 27 = 52 Jared McCann PIT 14 + 21 = 35 John Klingberg DAL 6 + 26 = 32 Travis Zajac NJD 9 + 16 = 25 Conor Sheary BUF 10 + 13 = 23
komento: 7 kuinka monta: 6
Jakub Vrana WSH 25 + 27 = 52 Jared McCann PIT 14 + 21 = 35 Conor Sheary BUF 10 + 13 = 23 Travis Zajac NJD 9 + 16 = 25 John Klingberg DAL 6 + 26 = 32 Mark Jankowski CGY 5 + 2 = 7
komento: 0
Vastaa lopuksi osion loppukyselyyn:
Kirjaudu sisään nähdäksesi tehtävän