Merkkijono
Ohjelmissa pitää usein käsitellä erilaista teksitietoa, esimerkiksi nimiä, osoitteita sekä erilaisia tunnuksia, kuten opiskelijanumeroita ja autojen rekisterinumeroita. Näitä voidaan käsitellä kätevästi merkkijonojen avulla. Merkkijono koostuu yhdestä tai useammasta peräkkäisestä merkistä. Merkkijono voi myös olla tyhjä, jolloin siinä ei ole yhtään merkkiä.
Merkkijono esitetään yksin- tai kaksinkertaisten lainausmerkkien avulla. Seuraavat kaksi sijoituskäskyä
>>> mjono = 'appelsiini'
>>> mjono = "appelsiini"
tarkoittavat täysin samaa.
Toisin kuin monissa muissa ohjelmointikielissä, Pythonissa ei eroteta toisistaan yksittäisiä merkkejä ja merkkijonoja. Myös yksittäiset merkit esitetään aina yhden merkin mittaisina merkkijonoina.
Pythonissa on tyyppi str
merkkijonojen esittämiseen. Merkkijonojen
käsittely Python-ohjelmissa muistuttaa hyvin paljon listojen käsittelyä.
Olennaisin ero on siinä, että listan sisältöä voidaan muuttaa listan
luomisen jälkeen, mutta merkkijonon sisältöä ei voida. Esimerkiksi
seuraavat Python-rivit ovat täysin mahdollisia:
>>> lukulista = [5, 2, 7]
>>> lukulista[1] = 4
>>> lukulista
[5, 4, 7]
Mutta sen sijaan seuraavat rivit aiheuttavat virhetilanteen, koska aikaisemmin luodun merkkijonon sisältöä ei voi muuttaa:
>>> sana = "sitruuna"
>>> sana[1] = "a"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
Merkkijonoja voidaan kuitenkin muuten käsitellä monilla samoilla
tavoilla kuin listoja. Esimerkiksi merkkijonon mjono
indeksillä
i
olevan kirjaimen saa selville ilmauksella mjono[i]
, vaikka
kirjainta ei pystykään vaihtamaan sijoituskäskyllä, esimerkiksi
>>> mjono = "appelsiini"
>>> print(mjono[3])
e
Merkkijonojen merkit voidaan myös käydä läpi for
-käskyn avulla
samalla tavalla kuin listan merkit. Esimerkiksi
>>> mjono = "appelsiini"
>>> for merkki in mjono:
... print(merkki)
...
a
p
p
e
l
s
i
i
n
i
Merkkijonosta voidaan myös ottaa alimerkkijonoja samalla tavalla kuin listoista antamalla hakasulkujen sisässä indeksialue, esimerkiksi
>>> mjono = "appelsiini"
>>> print(mjono[3:7])
elsi
Ennen kaksoispistettä oleva luku kertoo jälleen ensimmäisen alimerkkijonoon otettavan indeksin ja kaksoispisteen jälkeen oleva luku ensimmäisen indeksin, jota ei oteta mukaan alimerkkijonoon.
Merkkijonon pituuden saa selville funktiolla len:
>>> mjono = "appelsiini"
>>> print(len(mjono))
10
Operaattorilla in
pystyy tutkimaan sitä, esiintykö kirjain
merkkijonossa ja metodilla index
saa selville parametrina annetun
merkin ensimmäisen indeksin merkkijonossa:
>>> mjono = "appelsiini"
>>> if "i" in mjono:
... print("i esiintyy sanassa")
... print("indeksilla", mjono.index("i"))
...
i esiintyy sanassa
indeksilla 6
Operaattorin in
avulla voi tutkia myös sitä, esiintyykö yhtä
kirjainta pitempi merkkijono osana toista merkkijonoa:
>>> mjono = "appelsiini"
>>> print("elsii" in mjono)
True
>>> print("aelsi" in mjono)
False
Vaikka itse merkkijonoa ei voikaan muuttaa sen jälkeen, kun se on luotu, niin merkkijonoon viittaava muuttuja voidaan sijoituskäskyllä panna viittaamaan kokonaan toiseen merkkijonoon. Esimerkiksi seuraavat ohjelmarivit ovat täysin sallittuja:
>>> mjono = "appelsiini"
>>> print(mjono)
appelsiini
>>> mjono = "apelsiini"
>>> print(mjono)
apelsiini
Tässä alkuperäinen merkkijono "appelsiini"
ei kuitenkaan muutu
miksikään, vaan luodaan kokonaan uusi merkkijono "apelsiini"
, ja
muuttuja mjono
pannaan viittaamaan luotuun uuteen merkkijonoon.
Uusi merkkijono voi riippua vanhasta merkkijonosta. Pythonissa on
metodeita, joilla voidaan luoda kokonaan uusi, mutta vanhaa merkkijonoa
muistuttava merkkijono. Aikaisempaan merkkijonoon viitannut muuttuja
voidaan silloin sijoituskäskyllä panna viittaamaan luotuun, kokonaan
uuteen merkkijonoon. Esimerkiksi metodi lower
luo uuden merkkijonon,
joka sisältää muuten samat merkit kuin nykyinen merkkijono, mutta kaikki
isot kirjaimet on muutettu pieniksi kirjaimiksi.
>>> mjono = "AppelSiIni"
>>> mjono = mjono.lower()
>>> print(mjono)
appelsiini
Tämä metodi on hyvin kätevä silloin, kun pitää lukea käyttäjän syötettä ja verrata sitä johonkin muuhun tekstiin. Jos ei tiedetä, antaako käyttäjä syötteen isoina vai pieninä kirjaimina, voidaan syöte muuttaa ensin kokonaan pieniksi kirjaimiksi, jolloin sitä tarvitsee verrata vain pienillä kirjaimilla kirjoitettuun tekstiin.
Vastaavasti metodilla upper
voidaan luoda uusi merkkijono, joka
sisältää muuten samat merkit kuin nykyinen merkkijono, mutta kaikki
pienet kirjaimet on muutettu isoiksi kirjaimiksi.
>>> mjono = "AppelSiIni"
>>> mjono = mjono.upper()
>>> print(mjono)
APPELSIINI
Käyttäjän syötettä lukiessa tarvitaan usein myös metodia strip
. Se
luo uuden merkkijonon, jossa on poistettu nykyisen merkkijonon alussa ja
lopussa esiintyvät tyhjät merkit. Tyhjillä merkeillä tarkoitetaan
välilyönti-, tabulointi, rivinvaihto- ja sivunvaihtomerkkejä.
Tarkoituksena on poistaa luetun merkkijonon alusta ja lopusta
mahdolliset käyttäjän vahingossa kirjoittamat välilyönnit ja vastaavat.
Alla on esimerkki strip
-metodin käytöstä. Merkkijonot on nyt
tulostettu lainausmerkkien kanssa niin, että näkyy tarkemmin, mistä
merkkijono alkaa ja mihin se loppuu.
>>> mjono = " appelsiini "
>>> mjono
' \tappelsiini '
>>> mjono = mjono.strip()
>>> mjono
'appelsiini'
Esimerkin merkkijonossa aluksi esiintynyt merkki "\t"
tarkoittaa
tabulointi-merkkiä.
Useampi merkkijono voidaan yhdistää yhdeksi +
-operaattorin avulla,
ja merkkijonoja voi jopa monistaa *
-operaattorilla:
>>> etunimi = "Mikko"
>>> sukunimi = "Mallikas"
>>> kokonimi = etunimi + " " + sukunimi
>>> print(kokonimi)
Mikko Mallikas
>>> merkki = "&"
>>> rivi = 5 * merkki
>>> print(rivi)
&&&&&
>>> rivit = 3 * (rivi + "\n")
>>> print(rivit)
&&&&&
&&&&&
&&&&&
Yksi käytännössä usein tarvittava merkkijonoja käsittelevä metodi on
split
. Sen avulla voi jakaa merkkijonon useampaan osaan niin, että
jako tehdään aina halutun merkin tai pidemmän merkkijonon kohdalta. Oletusarvoisesti jako tehdään
välilyöntimerkin kohdalla. Jaon tuloksena syntyneet osamerkkijonot
voidaan tallentaa listaan seuraavan esimerkin mukaisesti:
>>> teksti = "Monta eri sanaa samassa merkkijonossa"
>>> sanat = teksti.split()
>>> print(sanat)
['Monta', 'eri', 'sanaa', 'samassa', 'merkkijonossa']
>>> for yksittainen_sana in sanat:
... print(yksittainen_sana)
...
Monta
eri
sanaa
samassa
merkkijonossa
Jaossa käytetty merkki (tässä tapauksessa välilyönti) ei kuulu
yhteenkään jaon tuloksena syntyneeseen osamerkkijonoon. Jos jako
halutaan tehdä jonkin muun kuin välilyöntimerkin kohdalta, annetaan tämä
merkki (tai pidempi merkkijono) parametrina split
-metodille, esimerkiksi
>>> teksti2 = "sanat/erotettu/toisistaan/kauttaviivalla"
>>> sanat2 = teksti2.split("/")
>>> print(sanat2)
['sanat', 'erotettu', 'toisistaan', 'kauttaviivalla']
Tässä esimerkissä näkyy myös hyvin se, että listan alkioiden ei tarvitse suinkaan olla lukuja, vaan lista voi sisältää myös esimerkiksi merkkijonoja.
Alla oleva animaatio esittää vielä esimerkin merkkijonon jakamisesta ja sen tuloksena syntyneen listan läpikäynnistä.
Jos jaon tuloksena syntyneitä osia halutaan käsitellä lukuarvoina, pitää
split
-operaation tuloksena syntyneen listan alkiot muuttaa
int
- tai float
-tyyppisiksi ennen laskutoimituksia. Alla on
esimerkki ohjelman osasta, joka lukee käyttäjältä yhden rivin,
jakaa sen osiin välilyönnin kohdalta, muuttaa osat kokonaisluvuiksi ja
tallentaa ne toiseen listaan:
print("Anna kaikki pisteet yhdella rivilla.")
print("Erota luvut toisistaan valilyonnilla.")
rivi = input()
osat = rivi.split()
lukulista = []
for osa in osat:
osa_lukuna = int(osa)
lukulista.append(osa_lukuna)
print("Alkuperainen lista:", osat)
print("Lukulista:", lukulista)
Näiden rivien suoritus voi näyttää esimerkiksi seuraavalta:
Anna kaikki pisteet yhdella rivilla.
Erota luvut toisistaan valilyonnilla.
22 33 56
Alkuperainen lista: ['22', '33', '56']
Lukulista: [22, 33, 56]
Alkuperäisen (split
-operaation tuloksena syntyneen) listan tulostuksessa
lukujen ympärillä on lainausmerkit. Se kertoo siitä, että Python-tulkin
mielestä listassa ei ole lukuja, vaan merkkijonoja. Toisen listan
alkiot taas ovat kokonaislukuja.
Metodin split
avulla edellisen luvun matriisi-esimerkkiä voidaan
muuttaa siten, että käyttäjä antaa matriisin kunkin rivin alkiot
yhdellä rivillä. Kokonainen rivi siis luetaan yhdellä input
-käskyllä,
jaetaan sitten osiin ja osat muutetaan desimaaliluvuiksi. Desimaalilukuja
sisältävä lista lisätään koko matriisia kuvaavaan kaksiulotteiseen
listaan. Alla on esitetty esimerkistä vain muutettu
funktio lue_matriisi
. Muu ohjelma ei muutu mitenkään.
def lue_matriisi(rivilkm, sarakelkm):
matriisi = []
print("Anna matriisin alkiot riveittain,")
print(rivilkm, "rivia ja", sarakelkm, "saraketta.")
print("Anna yhden rivin alkiot yhdella rivilla")
print("valilyonnilla erotettuna.")
i = 0
while i < rivilkm:
kayttajan_rivi = input()
osat = kayttajan_rivi.split()
if len(osat) != sarakelkm:
print("Vaara maara alkioita rivilla.")
else:
rivi_lukuina = [0.0] * sarakelkm
for j in range(sarakelkm):
rivi_lukuina[j] = float(osat[j])
matriisi.append(rivi_lukuina)
i += 1
return matriisi
Merkkijonoja voidaan myös vertailla operaattoreilla ==
, !=
,
<=
, >=
, <
ja >
. Esimerkiksi mjono1 == mjono2
on
tosi, jos muuttujan mjono1
viittaama merkkijono sisältää täsmälleen
samat merkit (samassa järjestyksessä) kuin muuttujan mjono2
viittaama merkkijono. Vertailussa pienet ja suuret kirjaimet katsotaan
eri merkeiksi. Muut operaattorit käyvät läpi vertailtavia merkkijonoja
merkki kerrallaan, kunnes kohdataan ensimmäistä kertaa eri merkit.
Tällöin näiden merkkien asema käytetyssä merkkikoodausjärjestelmässä
(siinä, miten kukin merkki esitetään tietokoneen muistissa
binäärilukuna) ratkaisee sen, kumpi merkkijonoista katsotaan toista
pienemmäksi. Käytännössä vertailu menee useimmiten aakkosjärjestyksen
mukaan, mutta kaikki isot kirjaimet ovat järjestyksessä ennen pieniä
kirjaimia ja skandinaavisten aakkosten (å, ä ja ö) osalta vertailu ei
toimi aakkosjärjestyksen mukaisesti.
Esimerkkinä merkkijonojen vertailusta esitetään vielä ohjelma, joka tekee lämpötilamuunnoksia fahrenheit-asteista celsius-asteiksi ja päinvastoin. Ohjelma ensin kysyy käyttäjältä, minä asteina hän haluaa lämpötilan antaa. Ohjelma lukee käyttäjältä muunnettavan lämpötilan ja tekee muunnoksen haluttuun suuntaan. Sen jälkeen ohjelma kysyy käyttäjältä, haluaako hän jatkaa antamalla toisen lämpötilan. Tätä jatketaan niin kauan, kunnes käyttäjä kertoo, että hän ei halua jatkaa.
def muunna_celsiuksiksi(F_asteet):
celsius_asteet = (F_asteet - 32) * 5.0 / 9.0
return celsius_asteet
def muunna_fahrenheiteiksi(C_asteet):
fahrenheit_asteet = 9.0/5.0 * C_asteet + 32
return fahrenheit_asteet
def main():
jatko = "kylla"
while jatko != "ei":
rivi = input("Mina asteina annat lampotilan (C/F)? ")
yksikko = rivi.upper()
if yksikko == "C":
asteet = float(input("Anna lampotila celsius-asteina: "))
fahrenheit = muunna_fahrenheiteiksi(asteet)
print(asteet, "C on", fahrenheit, "F.")
elif yksikko == "F":
asteet = float(input("Anna lampotila fahrenheit-asteina: "))
celsius = muunna_celsiuksiksi(asteet)
print(asteet, "F on", celsius, "C.")
else:
print("Virheellinen yksikko, pitaisi olla C tai F")
rivi = input("Haluatko jatkaa (kylla/ei)? ")
jatko = rivi.lower()
main()
Alla esimerkkiajo ohjelman suorituksesta:
Mina asteina annat lampotilan (C/F)? c
Anna lampotila celsius-asteina: 25.0
25.0 C on 77.0 F.
Haluatko jatkaa (kylla/ei)? kylla
Mina asteina annat lampotilan (C/F)? F
Anna lampotila fahrenheit-asteina: -40.0
-40.0 F on -40.0 C.
Haluatko jatkaa (kylla/ei)? kylla
Mina asteina annat lampotilan (C/F)? f
Anna lampotila fahrenheit-asteina: 92.0
92.0 F on 33.3333333333 C.
Haluatko jatkaa (kylla/ei)? Ei
Useammalle kuin yhdelle riville jakaantuvaa merkkijonoa voidaan merkitä kolmen lainausmerkin avulla, esimerkiksi
>>> teksti = """Hei, opiskelija!
... meidan Tosi on -pankistamme saat
... opintolainat edullisesti"""
>>> print(teksti)
Hei, opiskelija!
meidan Tosi on -pankistamme saat
opintolainat edullisesti
>>> mainos = '''Hei, opiskelija!
... tule suoraan omaan pankkiisi,
... ala vilkuile naapureihin'''
>>> print(mainos)
Hei, opiskelija!
tule suoraan omaan pankkiisi,
ala vilkuile naapureihin
Useammasta rivistä koostuva teksti voidaan tehdä ohjelmassa lisäämällä
rivinvaihtojen kohtaan \n
-merkkejä. Esimerkiksi seuraava ohjelma
pyytää käyttäjältä henkilön nimi- ja osoitetiedot sekä tekee niistä
merkkijonon, joka sisältää myös rivinvaihtoja.
def tee_osoite():
print("Anna seuraavan henkilon tiedot.")
etunimi = input("Etunimi: ")
sukunimi = input("Sukunimi: ")
katuosoite = input("Katuosoite: ")
postinumero = input("Postinumero: ")
postitoimipaikka = input("Postitoimipaikka: ")
osoite = etunimi + " " + sukunimi + "\n" + katuosoite + "\n" + \
postinumero + " " + postitoimipaikka.upper()
return osoite
def main():
print("Talla ohjelmalla voit syottaa ja tulostaa osoitteita.")
osoitteet = []
jatko = True
while jatko:
uusi_osoite = tee_osoite()
osoitteet.append(uusi_osoite)
vastaus = input("Haluatko antaa lisaa osoitteita (k/e)?\n")
if vastaus.lower() == "e":
jatko = False
print()
print("Antamasi osoitteet:")
for osoitetieto in osoitteet:
print(osoitetieto)
print()
main()
tee_osoite
muodostettu osoite lisätään listaan osoitteet
e
että E
kelpaavat
ohjelman suorituksen lopettaviksi vastauksiksiprint()
-käskyt ilman tulostettavaa tekstiä
lisäävät tyhjiä rivejä selkiyttämään ohjelman tulostusta.Esimerkki ohjelman suorituksesta:
Talla ohjelmalla voit syottaa ja tulostaa osoitteita.
Anna seuraavan henkilon tiedot.
Etunimi: Tiina
Sukunimi: Teekkari
Katuosoite: Jamerantaival 3 C 324
Postinumero: 02150
Postitoimipaikka: Espoo
Haluatko antaa lisaa osoitteita (k/e)?
k
Anna seuraavan henkilon tiedot.
Etunimi: Teemu
Sukunimi: Teekkari
Katuosoite: Servinkuja 4 B 44
Postinumero: 02150
Postitoimipaikka: espoo
Haluatko antaa lisaa osoitteita (k/e)?
e
Antamasi osoitteet:
Tiina Teekkari
Jamerantaival 3 C 324
02150 ESPOO
Teemu Teekkari
Servinkuja 4 B 44
02150 ESPOO
Käyttäjän syötettä lukiessa halutaan usein, että käyttäjä voi lopettaa
syötteen antamisen tyhjällä rivillä sen jälkeen, kun hän on antanut
haluamansa määrän rivejä. Kun syötettä luetaan input
-funktion
avulla, tunnistetaan tyhjä rivi siitä, että funktio palauttaa arvonaan
tyhjän merkkijonon ""
.
Seuraavassa esimerkissä luetaan käyttäjän antamia lukuja niin kauan, että käyttäjä antaa tyhjän rivin. Sen jälkeen ohjelma laskee ja tulostaa annettujen lukujen keskiarvon. Käyttäjän antama rivi muutetaan luvuksi vasta sen jälkeen, kun on ensin tutkittu, onko luettu merkkijono tyhjä. Jos muunnos tehtäisiin ennen merkkijonon tutkimista, ohjelma kaatuisi siihen, että tyhjää merkkijonoa ei voi muuttaa luvuksi.
def main():
print("Lasken keskiarvon antamistasi desimaaliluvuista.")
print("Lopeta tyhjalla rivilla.")
lukujen_maara = 0
summa = 0.0
loppu = False
while not loppu:
rivi = input()
if rivi == "":
loppu = True
else:
luku = float(rivi)
summa = summa + luku
lukujen_maara = lukujen_maara + 1
if lukujen_maara > 0:
keskiarvo = summa / lukujen_maara
print("Niiden keskiarvo on", keskiarvo)
else:
print("Et antanut yhtaan lukua.")
main()
Toisessa vaihtoehdossa tutkitaan while
-käskyn ehdossa, onko käyttäjä
antanut viimeksi tyhjän rivin. Tässä vaihtoehdossa käyttäjän syöte pitää
lukea ensimmäisen kerran jo ennen toistokäskyä. Uusi syöte luetaan aina
kunkin kierroksen lopuksi. Näin pidetään huoli siitä, että ohjelma ei
yritä muuttaa tyhjää riviä desimaaliluvuksi.
def main():
print("Lasken keskiarvon antamistasi desimaaliluvuista.")
print("Lopeta tyhjalla rivilla.")
lukujen_maara = 0
summa = 0.0
rivi = input()
while rivi != "":
luku = float(rivi)
summa = summa + luku
lukujen_maara = lukujen_maara + 1
rivi = input()
if lukujen_maara > 0:
keskiarvo = summa / lukujen_maara
print("Niiden keskiarvo on", keskiarvo)
else:
print("Et antanut yhtaan lukua.")
main()
Esimerkki ohjelman (kumman tahansa version) suorituksesta:
Lasken keskiarvon antamistasi desimaaliluvuista.
Lopeta tyhjalla rivilla.
-5.0
15.0
8.0
Niiden keskiarvo on 6.0
Toinen esimerkki, jossa käyttäjä antaa heti aluksi tyhjän rivin:
Lasken keskiarvon antamistasi desimaaliluvuista.
Lopeta tyhjalla rivilla.
Et antanut yhtaan lukua.