Kirjoittaja: Antti Laaksonen (2009).
⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠
Merkkijonot ovat keskeisessä asemassa ohjelmoinnissa, ja niitä on esiintynyt alusta asti runsaasti opassarjan ohjelmissa. Tähän mennessä merkkijonoja on tulostettu, yhdistetty toisiinsa ja vertailtu. Tämä opas kertoo merkkijonojen käsittelystä pintaa syvemmältä: merkkijono muodostuu merkeistä, joihin on usein tarpeen päästä käsiksi yksitellen.
Tässä vaiheessa on myös hyvä pysähtyä miettimään, mitä kaikkea jo opituilla taidoilla voi saada aikaan. Oppaan lopussa on joukko tehtäviä, jotka auttavat sisäistämään tähän mennessä käsiteltyjä asioita.
Merkkijono ja lista muistuttavat paljon toisiaan, ja usein voi ajatella, että merkkijono on lista merkkejä.
Esimerkiksi funktio len
kertoo, kuinka monta alkiota listassa on tai kuinka monta merkkiä merkkijonossa on. Vastaavasti for
-silmukka käy läpi listan alkiot tai merkkijonon merkit. Edelleen listan alkioihin ja merkkijonon merkkeihin voi viitata hakasulkujen avulla.
Seuraava ohjelma ilmoittaa merkkijonon merkkien määrän ja tulostaa sitten toisen ja viidennen merkin ja vielä kaikki merkit alusta loppuun.
# -*- coding: latin-1 -*- mjono = raw_input("Kirjoita merkkijono: ") print "Merkkien määrä:", len(mjono) print "Toinen merkki:", mjono[1] print "Viides merkki:", mjono[4] print "Kaikki merkit:" for merkki in mjono: print merkki
Ohjelman tulostus voi näyttää seuraavalta:
Kirjoita merkkijono: testi Merkkien määrä: 5 Toinen merkki: e Viides merkki: i Kaikki merkit: t e s t i
Merkkijonon ja listan tärkeä ero on, että merkkijonon merkkejä ei voi muuttaa samaan tapaan kuin listan alkioita. Esimerkiksi seuraava ohjelma ei toimi odotetulla tavalla vaan aiheuttaa virheen:
# -*- coding: latin-1 -*- testi = "esimörkki" testi[4] = "e" # ei muuta ö:tä e:ksi!
Jos ohjelman täytyy tehdä muutos merkkijonoon, sen täytyy muodostaa merkkijono uudestaan osista. Käytännössä yllä olevan korjauksen voisi toteuttaa esimerkiksi seuraavasti:
# -*- coding: latin-1 -*- testi = "esimörkki" testi = testi[:4] + "e" + testi[5:]
Tässä merkinnät testi[:4]
ja testi[5:]
viittaavat merkkijonon alkuosaan ja loppuosaan muutettavan merkin ympärillä. Seuraavaksi nähdään, miten tällaisia merkintöjä muodostetaan.
Merkkijonosta ja listasta voi erottaa osia hakasulkujen avulla. Listojen käsittelyä vastaavasti mjono[0]
viittaa merkkijonon ensimmäiseen merkkiin, mjono[1]
viittaa toiseen merkkiin, mjono[2]
viittaa kolmanteen merkkiin jne.
Hakasulkumerkinnän yleisemmät muodot ovat [a]
ja [a:b]
, jossa a
ja b
ovat listan tai merkkijonon kohtia. Merkintä [a]
erottaa yhden alkion tai merkin, ja merkintä [a:b]
erottaa monta alkiota tai merkkiä. Positiivinen kohta lasketaan alusta ja negatiivinen lopusta.
Merkinnässä [a:b]
erotettava osa alkaa kohdasta a
ja päättyy juuri ennen kohtaa b
. Jos a
puuttuu, osa alkaa listan tai merkkijonon alusta. Jos b
puuttuu, osa päättyy listan tai merkkijonon loppuun.
Merkkijonon "esimerkki"
kohdat alusta ja lopusta ovat:
e s i m e r k k i alusta 0 1 2 3 4 5 6 7 8 lopusta -9 -8 -7 -6 -5 -4 -3 -2 -1
Seuraava ohjelma tulostaa joukon merkkijonon osia:
# -*- coding: latin-1 -*- mjono = "esimerkki" print mjono[1] # s print mjono[-4] # r print mjono[1:6] # simer print mjono[-4:7] # rk print mjono[3:-2] # merk print mjono[:4] # esim print mjono[-2:] # ki
Esimerkiksi mjono[1:6]
on "simer"
, koska osa alkaa kohdasta 1 ja päättyy kohtaan 5. Vastaavasti mjono[3:-2]
on "merk"
, koska osa alkaa kohdasta 3 ja päättyy kohtaan -2. Merkinnät mjono[:4]
ja mjono[-2:]
tarkoittavat merkkijonon 4 ensimmäistä ja 2 viimeistä merkkiä.
Hakasulkumerkintää voi käyttää vastaavasti listojen käsittelyssä. Esimerkiksi jos lista
on [1, 2, 3, 4, 5]
, merkintä lista[-1]
tarkoittaa lukua 5
, merkintä lista[1:4]
tarkoittaa listaa [2, 3, 4]
ja merkintä lista[-2:]
tarkoittaa listaa [4, 5]
.
Suomalaisen henkilötunnuksen viimeinen merkki on tarkistusmerkki, jonka voi laskea tunnuksen alkuosan perusteella. Tarkistusmerkki lasketaan jakamalla henkilötunnuksen alkuosan numeroiden muodostama luku 31:llä ja valitsemalla jakojäännöstä vastaava tarkistusmerkki seuraavasta taulukosta:
0 | 0 | 8 | 8 | 16 | H | 24 | S |
1 | 1 | 9 | 9 | 17 | J | 25 | T |
2 | 2 | 10 | A | 18 | K | 26 | U |
3 | 3 | 11 | B | 19 | L | 27 | V |
4 | 4 | 12 | C | 20 | M | 28 | W |
5 | 5 | 13 | D | 21 | N | 29 | X |
6 | 6 | 14 | E | 22 | P | 30 | Y |
7 | 7 | 15 | F | 23 | R |
Esimerkiksi jos henkilötunnuksen alkuosa on 150882-193
, tarkistusmerkki on H
, koska luvun 150882193 jakojäännös 31:llä on 16 ja taulukossa kohdassa 16 on merkki H
. Koko henkilötunnus on siis 150882-193H
.
Seuraava ohjelma laskee tarkistusmerkin henkilötunnuksen alkuosan perusteella ja muodostaa koko henkilötunnuksen:
# -*- coding: latin-1 -*- tunnus = raw_input("Henkilötunnuksen alkuosa: ") luku = int(tunnus[:6] + tunnus[-3:]) jaannos = luku % 31 merkit = "0123456789ABCDEFHJKLMNPRSTUVWXY" vika = merkit[jaannos] print "Viimeinen merkki:", vika tunnus = tunnus + vika print "Koko henkilötunnus:", tunnus
Ohjelman tulostus voi olla seuraava:
Henkilötunnuksen alkuosa: 150882-193 Viimeinen merkki: H Koko henkilötunnus: 150882-193H
Henkilötunnuksen alkuosassa on ensin päivämäärä (6 numeroa), sitten vuosisatamerkki (1900-luvulla syntyneillä viiva) ja lopuksi yksilötunnus (3 numeroa). Ohjelma muodostaa luvun päivämäärästä ja yksilötunnuksesta, laskee sen jakojäännöksen 31:llä ja valitsee jakojäännöstä vastaavan merkin.
Seuraava ohjelma etsii tekstistä käyttäjän antamaa hakusanaa:
# -*- coding: latin-1 -*- teksti = "Henrikki on urhea ritari." sana = raw_input("Hakusana: ") for alku in range(len(teksti)): loppu = alku + len(sana) if teksti[alku:loppu] == sana: print "Löytyi kohdasta", alku
Tässä on ohjelman mahdollisia tulostuksia:
Hakusana: urhea Löytyi kohdasta 12
Hakusana: ri Löytyi kohdasta 3 Löytyi kohdasta 18 Löytyi kohdasta 22
Ohjelma käy läpi kaikki tekstin kohdat ja vertaa jokaisessa kohdassa hakusanaa tekstin sisältöön. Esimerkiksi kun hakusana on "urhea"
, ohjelman suoritus etenee seuraavasti:
"Henri"
ja "urhea"
."enrik"
ja "urhea"
."nrikk"
ja "urhea"
."rikki"
ja "urhea"
."ikki "
ja "urhea"
.Vihdoin kohdassa 12 tekstissä lukee "urhea"
ja ohjelma ilmoittaa osumasta.
Tässä on toinen tapa toteuttaa hakusanan etsintä:
# -*- coding: latin-1 -*- teksti = "Henrikki on urhea ritari." sana = raw_input("Hakusana: ") kohta = teksti.find(sana, 0) while kohta != -1: print "Löytyi kohdasta", kohta kohta = teksti.find(sana, kohta + 1)
Nyt käytössä on merkkijonon metodi find
, jonka parametrit ovat etsittävä merkkijono ja haun aloituskohta. Metodi palauttaa merkkijonon ensimmäisen esiintymiskohdan aloituskohdan jälkeen tai luvun -1, jos haku on tulokseton.
Seuraava ohjelma jakaa käyttäjän antaman lauseen sanoihin:
# -*- coding: latin-1 -*- lause = raw_input("Anna lause: ") alku = 0 for loppu in range(len(lause)): if lause[loppu] == " ": print lause[alku:loppu] alku = loppu + 1 print lause[alku:]
Ohjelman tulostus voi olla seuraava:
Anna lause: Mitähän tämä ohjelma tekee? Mitähän tämä ohjelma tekee?
Ohjelma käy läpi kaikki tekstin kohdat ja tutkii jokaisessa kohdassa, onko siinä kohdassa välilyönti eli kahden sanan väli. Ohjelma pitää muistissa sanan aloituskohtaa muuttujassa alku
. Silmukan päätteeksi ohjelma tulostaa viimeisen sanan, jonka jälkeen ei tule välilyöntiä.
Tässä on toinen tapa jakaa lause sanoihin:
# -*- coding: latin-1 -*- lause = raw_input("Anna lause: ") sanat = lause.split(" ") for sana in sanat: print sana
Nyt käytössä on merkkijonon metodi split
, joka jakaa merkkijonon osiin halutun erotusmerkin kohdalta ja muodostaa osista listan. Tässä tapauksessa sopiva erotusmerkki on kahden sanan välissä oleva välilyönti.
Äskeiset esimerkit osoittivat, että merkkijonon metodit find
ja split
eivät ole välttämättömiä, koska saman asian voi toteuttaa muuttujien, silmukoiden ja hakasulkujen avulla. Sama pätee moneen muuhun Python-kielen ominaisuuteen: ne helpottavat ohjelmointia mutta eivät ole korvaamattomia.
Tähän mennessä opittuja asioita soveltamalla voi toteuttaa hyvin monenlaisia ohjelmia. Ohjelma voi säilyttää tietoa muuttujissa, valita ehtojen avulla suoritettavan koodin tilanteesta riippuen ja suorittaa silmukoiden avulla samaa koodia monta kertaa peräkkäin.
Seuraavassa on joukko tehtäviä, joiden avulla voit kehittää ohjelmointitaitoasi:
Kirjoita ohjelma, joka tarkistaa, onko vuosi karkausvuosi. Vuosi on karkausvuosi, jos se on jaollinen 4:llä. Kuitenkin jos vuosi on jaollinen 100:lla, se on karkausvuosi vain, jos se on jaollinen myös 400:lla.
Ohjelman tulostus voi olla seuraava:
Anna vuosi: 2009 Vuosi 2009 ei ole karkausvuosi.
Kirjoita ohjelma, joka laskee summan 1 + 2 + 3 + ..., kun ohjelmalle annetaan suurin summaan kuuluva luku. Esimerkiksi jos suurin luku on 5, ohjelman täytyy laskea summa 1 + 2 + 3 + 4 + 5.
Ohjelman tulostus voi olla seuraava:
Anna suurin luku: 5 1 + 2 + 3 + 4 + 5 = 15
Kirjoita ohjelma, joka kysyy käyttäjältä lukuja, kunnes käyttäjä antaa negatiivisen luvun. Sitten ohjelma ilmoittaa pienimmän ja suurimman käyttäjän antaman luvun.
Ohjelman tulostus voi olla seuraava:
Anna luku: 7 Anna luku: 3 Anna luku: 14 Anna luku: 8 Anna luku: -1 Pienin luku: 3 Suurin luku: 14
Kirjoita ohjelma, joka tulostaa kuvion seuraavan mallin mukaisesti:
Anna kerrosten määrä: 4 * *** ***** *******
Kirjoita ohjelma, joka laskee, kuinka monta vokaalia ja konsonanttia sanassa on.
Ohjelman tulostus voi olla seuraava:
Anna sana: esimerkki Sanassa on 4 vokaalia ja 5 konsonanttia.
Kirjoita ohjelma, joka tulostaa kertotaulun. Ohjelmalle annetaan kaksi lukua, kertotaulun pystyrivien ja vaakarivien määrä.
Ohjelman tulostus voi olla seuraava:
Pystyrivit: 5 Vaakarivit: 8 1 2 3 4 5 6 7 8 2 4 6 8 10 12 14 16 3 6 9 12 15 18 21 24 4 8 12 16 20 24 28 32 5 10 15 20 25 30 35 40
Kirjoita ohjelma, joka tarkistaa, onko sana palindromi. Sana on palindromi, jos se on sama alusta loppuun ja lopusta alkuun luettuna.
Ohjelman tulostus voi olla seuraava:
Anna sana: sytytys Sana on palindromi!
Kirjoita ohjelma, joka tarkistaa, ovatko kaksi sanaa anagrammeja. Sanat ovat anagrammeja, jos niissä on jokaista kirjainta yhtä monta.
Ohjelman tulostus voi olla seuraava:
Anna 1. sana: mikrosekunti Anna 2. sana: sointumerkki Sanat ovat anagrammeja!
Kirjoita ohjelma, joka etsii kahden merkkijonon pisimmän yhteisen osan. Esimerkiksi jos merkkijonot ovat "tausta"
ja "muste"
, pisin yhteinen osa on "ust"
.
Ohjelman tulostus voi olla seuraava:
Anna 1. sana: tausta Anna 2. sana: muste Pisin yhteinen osa: ust
Kirjoita ohjelma, joka tulostaa kuvion seuraavan mallin mukaisesti:
Anna kerrosten määrä: 4 DDDDDDD DCCCCCD DCBBBCD DCBABCD DCBBBCD DCCCCCD DDDDDDD
Kirjoita ohjelma, joka tulostaa kaikki alkuluvut annettuun lukuun asti. Alkuluku on positiivinen kokonaisluku, joka on jaollinen ainoastaan luvulla 1 ja itsellään. Lisäksi on sovittu, että luku 1 ei ole alkuluku.
Ohjelman tulostus voi olla seuraava:
Anna suurin luku: 20 2 3 5 7 11 13 17 19
Kirjoita ohjelma, joka tulostaa suomeksi luvut 1–1000. Ohjelmassa täytyy olla alle 50 riviä!
Ohjelman tulostus on seuraava:
yksi kaksi kolme ... (välissä rivejä) yhdeksänsataayhdeksänkymmentäkahdeksan yhdeksänsataayhdeksänkymmentäyhdeksän tuhat
Hyvä opassarja. En ole ennen ohjelmoinut ja Pythonilla olen alkanut ohjelmoinnin perusteita harjoitella ja jotain jopa oppinut. Jotkut tässä osassa olleet tehtävät kuitenkin askarruttavat, joten voisiko joku kokeneempi ohjelmoija antaa vastauksia tehtäviin?? :) En viitsisi jatkaa seuraaviin osiin ennenkuin tämän osan tehtävät on tehty..
Täällä päässä tökkii myös osa tehtävistä. Näkisikö oppaan tekijä vielä sen verran vaivaa että laittaisi tehtävien koodaukset näkyville erilliselle sivulle?
Nämä ovat oikein mukavia tehtäviä.
Näiden kanssa saa pähkäillä, en olisi uskonut, että 1. tehtävän vastaus olisi ollut niin helppo, kuin se sitten olikin.
Tuossa 6. tehtävän tulosteessa on ainakin minun silmääni pystyrivejä 8 ja vaakarivejä 5 eikä päinvastoin. Mitä vikaa on muuten termeissä rivi ja sarake?
Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.