Kirjautuminen

Haku

Tehtävät

Opasarkisto: Python 2 -ohjelmointi: Osa 6 - Merkkijonot

  1. Osa 1 - Ensimmäinen ohjelma
  2. Osa 2 - Tiedon käsittely
  3. Osa 3 - Ehtorakenteet
  4. Osa 4 - Toistorakenteet
  5. Osa 5 - Listojen käsittely
  6. Osa 6 - Merkkijonot
  7. Osa 7 - Omat funktiot
  8. Osa 8 - Tiedostot ja virheet
  9. Osa 9 - Standardikirjasto
  10. Osa 10 - Tietorakenteet
  11. Osa 11 - Alkeita edemmäs
  12. Osa 12 - Yhteenveto
  13. Liite 1 - Asennus ja käyttö
  14. Liite 2 - Python ja ääkköset

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

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.

Osien erotus

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

Esimerkki: Henkilötunnus

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:

00      88      16H      24S
119917J25T
2210A18K26U
3311B19L27V
4412C20M28W
5513D21N29X
6614E22P30Y
7715F23R

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.

Esimerkki: Sanahaku

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:

  1. Ohjelma vertaa merkkijonoja "Henri" ja "urhea".
  2. Ohjelma vertaa merkkijonoja "enrik" ja "urhea".
  3. Ohjelma vertaa merkkijonoja "nrikk" ja "urhea".
  4. Ohjelma vertaa merkkijonoja "rikki" ja "urhea".
  5. Ohjelma vertaa merkkijonoja "ikki " ja "urhea".
  6. (jne.)

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.

Esimerkki: Lauseen sanat

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.

Tehtäviä

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:

  1. 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.
  2. 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
  3. 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
  4. Kirjoita ohjelma, joka tulostaa kuvion seuraavan mallin mukaisesti:

    Anna kerrosten määrä: 4
       *
      ***
     *****
    *******
  5. 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.
  6. 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
  7. 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!
  8. 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!
  9. 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
  10. Kirjoita ohjelma, joka tulostaa kuvion seuraavan mallin mukaisesti:

    Anna kerrosten määrä: 4
    DDDDDDD
    DCCCCCD
    DCBBBCD
    DCBABCD
    DCBBBCD
    DCCCCCD
    DDDDDDD
  11. 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
  12. 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

Kommentit

Creamy [29.12.2010 20:40:28]

#

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

Ezio [22.02.2011 13:45:26]

#

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?

Rugila [06.06.2012 10:55:26]

#

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.

Legu [08.01.2013 18:12:07]

#

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?

Kirjoita kommentti

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.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta