35 Lugemine failist

Lugemine failist. Tõde ja õigus

Failist lugemist for-tsükli abil oleme varem mitmel korral kasutanud:

fail = open("andmed.txt", encoding="UTF-8")
for rida in fail:
print("Lugesin sellise rea: " + rida)
fail.close()
fail = open("andmed.txt", encoding="UTF-8") for rida in fail: print("Lugesin sellise rea: " + rida) fail.close()
fail = open("andmed.txt", encoding="UTF-8")
for rida in fail:
    print("Lugesin sellise rea: " + rida)
fail.close()

Pikema teksti lugemise ja analüüsimise näitena võtame käsile Anton Hansen Tammsaare “Tõe ja õiguse” 1. köite. Tegemist on meie rahva ühe tüvitekstiga, mida siin omalaadselt käsitleme. Valdur Mikita on Sirbis kirjutanud: “Rahvas, kelle kõige kuulsam kirjandusteos on viieköiteline sookuivendamise käsiraamat, ei saa olla normaalne – ja ei peagi. Võimalik, et meil on ilmaruumis hoopis üks teine asi ajada.”

Kõigepealt tuleb tekst arvutisse laadida siit. (Kes tahab, võib proovida ka programselt veebist lugemist.)

Järgmine programm loendab, mitu korda on tekstis sõna “tõde” ja mitu korda “õigus”.

Näiteprogramm. Tõed ja õigused

f = open("anton_hansen_tammsaare_tode_ja_oigus_i.txt", encoding='UTF-8')
tõde = 0 # loendaja
õigus = 0 # loendaja
for rida in f: # ridade kaupa
sõnad = rida.split() # rea sõnad järjendisse
for s in sõnad: # sõnade kaupa
if s == "tõde":
tõde += 1
if s == "õigus":
õigus += 1
print("Failis sõna 'tõde' on", tõde, "korda.")
print("Failis sõna 'õigus' on", õigus, "korda.")
f.close()
f = open("anton_hansen_tammsaare_tode_ja_oigus_i.txt", encoding='UTF-8') tõde = 0 # loendaja õigus = 0 # loendaja for rida in f: # ridade kaupa sõnad = rida.split() # rea sõnad järjendisse for s in sõnad: # sõnade kaupa if s == "tõde": tõde += 1 if s == "õigus": õigus += 1 print("Failis sõna 'tõde' on", tõde, "korda.") print("Failis sõna 'õigus' on", õigus, "korda.") f.close()
f = open("anton_hansen_tammsaare_tode_ja_oigus_i.txt", encoding='UTF-8')
 
tõde = 0   # loendaja
õigus = 0  # loendaja
 
for rida in f:           # ridade kaupa
    sõnad = rida.split() # rea sõnad järjendisse
    for s in sõnad:      # sõnade kaupa
        if s == "tõde":
            tõde += 1
        if s == "õigus":
            õigus += 1
 
print("Failis sõna 'tõde' on", tõde,  "korda.")
print("Failis sõna 'õigus' on", õigus, "korda.")
 
f.close()

Enesekontroll (1 küsimus)

Sõneotsingu täiendamine

See programm leidis sõnade “tõde” ja “õigus” arvud ainult juhul, kei neile ei järge teisi sümboleid. Kui tahame, et arvesse tuleksid ka need juhud, kus vahetult sõna järel on mingi kindel kirjavahemärk, siis saame kasutada järgmisi võrdlusi. Nii võetakse arvesse need juhud, kus sõna järel on punkt, koma või küsimärk:

if s.strip(".,?") == "tõde":
tõde += 1
if s.strip(".,?") == "õigus":
õigus += 1
if s.strip(".,?") == "tõde": tõde += 1 if s.strip(".,?") == "õigus": õigus += 1
if s.strip(".,?") == "tõde":
    tõde += 1
if s.strip(".,?") == "õigus":
    õigus += 1

Nüüd vaatame varianti, kus kontrollitakse, kas sõna “tõde” (“õigus”) sisaldub vaadeldavas sõnes:

if "tõde" in s:
tõde += 1
if "õigus" in s:
õigus += 1
if "tõde" in s: tõde += 1 if "õigus" in s: õigus += 1
if "tõde" in s:
    tõde += 1
if "õigus" in s:
    õigus += 1

Kui tahame suurte tähtedega variante arvesse võtta, siis saame seda teha nii:

if "tõde" in s.lower():
tõde += 1
if "õigus" in s.lower():
õigus += 1
if "tõde" in s.lower(): tõde += 1 if "õigus" in s.lower(): õigus += 1
if "tõde" in s.lower():
    tõde += 1
if "õigus" in s.lower():
    õigus += 1

See lahendus leiab ka nn valepositiivseid vastuseid, näiteks sõna “tõde” sisaldub sõnas “tõdemus”, mis on hoopis erineva tähendusega. Inimkeelsete tekstide põhjalikum automaatne töötlemine on küllaltki keerukas ja siinsetes materjalides me seda ei vaatle.

Veel failist lugemisest. Funktsioon readline

Vaatleme veel mõningaid võimalusi, kuidas failidest andmeid kätte saada. Alustame funktsiooniga

readline
readline, mis võtab failist järgmise rea.

Esialgu teeme käsitsi faili andmed2.txt. Esimesel real on inimese nimi, teisel real vanus (täisarvuna) ning kolmandal real meiliaadress. Fail peab olema plain-text kujul (laiendiga .txt).

Näiteprogramm. Faili lugemine readline abil

f = open("andmed2.txt", encoding="UTF-8")
nimi = f.readline()
vanus = f.readline()
aadress = f.readline()
print("Nimi:", nimi)
print("Vanus:", vanus, "aastat")
print("Aadress:", aadress)
f.close()
f = open("andmed2.txt", encoding="UTF-8") nimi = f.readline() vanus = f.readline() aadress = f.readline() print("Nimi:", nimi) print("Vanus:", vanus, "aastat") print("Aadress:", aadress) f.close()
f = open("andmed2.txt", encoding="UTF-8")
 
nimi = f.readline()
vanus = f.readline()
aadress = f.readline()
 
print("Nimi:", nimi)
print("Vanus:", vanus, "aastat")
print("Aadress:", aadress)
 
f.close()

Käsk

open
open otsib failisüsteemist üles soovitud faili ja tagastab viite sellele (antud näites salvestasime selle viite muutujasse f, mis on levinud nimi failide tähistamiseks). Kui tahame avada faili samast kaustast, kus asub programm, siis piisab vaid failinimest koos laiendiga:
f = open('andmed2.txt')
f = open('andmed2.txt'). Selleks, et täpitähed õigesti paistaksid, täpsustame kodeeringut argumendiga
encoding="UTF-8"
encoding="UTF-8"
.

Rida

nimi = f.readline()
nimi = f.readline() loeb failist ühe rea, milles on meie näites isiku nimi, ning annab selle väärtuse muutujale nimi. Järgmisel korral sama käsku kasutades loetakse järgmine rida – meie näites vanus.

Käsk

f.close()
f.close() paneb faili kinni. Faili sulgemata jätmine võib põhjustada igasuguseid muresid, näiteks võib korduvatel käivitustel olla probleeme juba avatud faili avamisega.

Programmi tööle pannes näeme, et väljundis tekib üleliigseid tühje ridu. Nimelt jäetakse iga rea lõppu alles ka failist pärinev reavahetuse sümbol. Kuna

print
print lisab omalt poolt veel ühe reavahetuse, siis saamegi neid liigselt. Liigse reavahetuse eemaldamiseks saame kasutada näiteks meetodit 
strip
strip, mis ilma argumente määramata eemaldab whitespace-sümbolid (tühikud, reavahetused jms):

nimi = f.readline().strip()
nimi = f.readline().strip()
nimi = f.readline().strip()

Funktsioonid readlines ja read

Lisaks funktsioonile

readline
readline saab failist info kätte ka funktsiooniga
readlines
readlines:

f = open("andmed2.txt", encoding="UTF-8")
loetud = f.readlines()
f.close() # faili ei lähe enam vaja
print(loetud)
f = open("andmed2.txt", encoding="UTF-8") loetud = f.readlines() f.close() # faili ei lähe enam vaja print(loetud)
f = open("andmed2.txt", encoding="UTF-8")
loetud = f.readlines()
f.close() # faili ei lähe enam vaja
print(loetud)

Näeme, et muutujas loetud on list, mille iga element on üks rida näidatud failist.

Veebist lugemisel kasutasime funktsiooni

read
read. Seda saame kasutada ka failist lugemise korral. Nii saame kogu faili sisu ühe sõnena:

f = open("andmed2.txt", encoding="UTF-8")
loetud = f.read()
f.close() # faili ei lähe enam vaja
print(loetud)
f = open("andmed2.txt", encoding="UTF-8") loetud = f.read() f.close() # faili ei lähe enam vaja print(loetud)
f = open("andmed2.txt", encoding="UTF-8")
loetud = f.read()
f.close() # faili ei lähe enam vaja
print(loetud)

Võime piirata loetavate märkide arvu (näiteks 5 sümbolit):

f = open("andmed2.txt", encoding="UTF-8")
loetud = f.read(5)
f.close() # faili ei lähe enam vaja
print(loetud)
f = open("andmed2.txt", encoding="UTF-8") loetud = f.read(5) f.close() # faili ei lähe enam vaja print(loetud)
f = open("andmed2.txt", encoding="UTF-8")
loetud = f.read(5)
f.close() # faili ei lähe enam vaja
print(loetud)

Etteantud märkide arv võib olla ka üks, siis loetakse märke ühekaupa.

Järgmine programm on inspireeritud asjaolust, et SMSi saatmisel on õ-tähte sisaldava sõnumi maksimaalne lubatud pikkus märgatavalt väiksem, sest siis kasutatakse teistsugust kodeeringut. Sageli asendatakse täht õ numbriga 6 (arvatavalt pärineb traditsioon vanade mobiiltelefonide ajast, kus õ-täht üldse puudus). Teeme programmi, mis asendaks kõik õ-tähed sümboliga 6:

Näiteprogramm. Õ asendamine I

f = open("sms.txt", encoding="UTF-8")
while True: # lõpmatu tsükkel, kui ei katkestata
sümbol = f.read(1) # loetakse üks sümbol
if sümbol == "": # kui enam sümboleid pole
break # tsükkel katkestatakse
if sümbol == "õ":
print("6", end = "") # reavahetust ei tule
else:
print(sümbol, end = "") # reavahetust ei tule
f.close() # faili ei lähe enam vaja
f = open("sms.txt", encoding="UTF-8") while True: # lõpmatu tsükkel, kui ei katkestata sümbol = f.read(1) # loetakse üks sümbol if sümbol == "": # kui enam sümboleid pole break # tsükkel katkestatakse if sümbol == "õ": print("6", end = "") # reavahetust ei tule else: print(sümbol, end = "") # reavahetust ei tule f.close() # faili ei lähe enam vaja
f = open("sms.txt", encoding="UTF-8")
 
while True:                     # lõpmatu tsükkel, kui ei katkestata
    sümbol = f.read(1)          # loetakse üks sümbol
    if sümbol == "":            # kui enam sümboleid pole
        break                   # tsükkel katkestatakse
    if sümbol == "õ":
        print("6", end = "")    # reavahetust ei tule
    else:
        print(sümbol, end = "") # reavahetust ei tule
 
f.close()                       # faili ei lähe enam vaja

Sama ülesande saab lahendada ka kahe for-tsükliga. Välimine tsükkel tegutseb ridade kaupa. Sisemisel võetakse vastavast reast sümboleid:

Näiteprogramm. Õ asendamine II

f = open("sms.txt", encoding="UTF-8")
for rida in f: # ridade kaupa
for sümbol in rida: # sümbolite kaupa
if sümbol == "õ":
print("6", end = "") # reavahetust ei tule
else:
print(sümbol, end = "") # reavahetust ei tule
f.close() # faili ei lähe enam vaja
f = open("sms.txt", encoding="UTF-8") for rida in f: # ridade kaupa for sümbol in rida: # sümbolite kaupa if sümbol == "õ": print("6", end = "") # reavahetust ei tule else: print(sümbol, end = "") # reavahetust ei tule f.close() # faili ei lähe enam vaja
f = open("sms.txt", encoding="UTF-8")
 
for rida in f:                      # ridade kaupa
    for sümbol in rida:             # sümbolite kaupa
        if sümbol == "õ":
            print("6", end = "")    # reavahetust ei tule
        else:
            print(sümbol, end = "") # reavahetust ei tule
 
f.close()                           # faili ei lähe enam vaja

Toome ka kolmanda variandi, kus funktsiooni

read
read kasutades saame faili kogu sisu ühe sõnena käsitleda. Selles sõnes muudame funktsiooni
replace
replace abil kõik tähed õ numbriteks 6:

Näiteprogramm. Õ asendamine III

f = open("sms.txt", encoding="UTF-8")
failisisu = f.read()
asendatudõ = failisisu.replace("õ","6")
print(asendatudõ)
f.close()
f = open("sms.txt", encoding="UTF-8") failisisu = f.read() asendatudõ = failisisu.replace("õ","6") print(asendatudõ) f.close()
f = open("sms.txt", encoding="UTF-8")
 
failisisu = f.read()
 
asendatudõ = failisisu.replace("õ","6")
 
print(asendatudõ)
 
f.close()

Enesekontroll (1 ülesanne)

Litsents

Icon for the Creative Commons Attribution 4.0 International License

Programmeerimine on loodud Eno Tõnisson, Tauno Palts, Merilin Säde, Kaarel Tõnisson jt poolt Creative Commons Attribution 4.0 International License litsentsi alusel, kui pole teisiti märgitud.

Jaga seda raamatut