Albus Percival Wulfric Brian Dumbledore
Ocena 6
Za oceno 6 bo potrebno pokazati, da znamo brati datoteke csv ter delati z nizi in slovarji.
V datoteki osebe.csv se nahajajo polna imena vseh oseb iz Harryja Potterja (žal tudi iz kasnejših "dodatkov") in povezave na strani s podatki o njih na Wikidata. Preberite podatke iz datoteke in jih shranite v slovar z imenom
osebe
: ključi naj bodo polna imena oseb, pripadajoče vrednosti pa povezave. (Torej: drugi stolpec so ključi, prvi stolpec so vrednosti.)Program naj ne bo napisan za to specifično vsebino datoteke! Če spremenimo vsebino datoteke, tako da vsebuje osebe iz romana Vojna in mir, mora pač sestaviti slovar teh oseb. Računajte pa, da bo datoteki vedno ime osebe.csv.
Pomembno: datoteka je v istem direktoriju kot programi in program naj datoteko odpre z
open("osebe.csv")
, brez imen direktorijev! Nobenihopen("c:\Users\janez\programiranje\naloga11\oseba.csv")
!Napišite funkcijo
brez_dodatkov(ime)
, ki prejme polno ime osebe in vrne ime te osebe brez "dodatkov". Klicbrez_dodatkov("Mrs. Molly Weasley")
vrne"Molly Weasley"
, klicbrez_dodatkov("Cygnus Black III")
vrne"Cygnus Blake"
in klicbrez_dodatkov("Madame Rolanda Hooch")
vrne"Rolanda Hooch"
. Dodatki, ki jih morate odstraniti, so'Mr. ', 'Mrs. ', ' III', ' II', ' I', 'the ', 'The ', ' Jr.', 'Sir ', 'Madam ', 'Madame '
. (V seznamu sem prijazno dodal presledke pred ali za "dodatek"; to bi vam lahko pomagalo, če vam ne, pa jih pobrišite.)Pazi:
"Sirius Black III"
mora postati"Sirius Black"
, ne"ius Black"
!Napišite funkcijo
po_priimkih()
, ki vrne slovar, katerega ključi so priimki oseb, vrednosti pa množice (prvih) imen oseb s takšnim priimkom. Pri tem moraš iz imena pobrisati "dodatke" - kot je opisano zgoraj.- Če je za osebo znano le eno ime (Kreacher, Nagini), brez priimka, naj se ne pojavi v slovarju.
- Če ima oseba več imen, je priimek zadnji, ime pa je prvo. V
"Albus Percival Wulfric Brian Dumbledore"
je priimek Dumbledore, ime pa Albus.
V slovarju, ki ga vrne
po_priimkih
, je pri ključu"Dumbledore"
vrednost{'Albus', 'Ariana', 'Percival', 'Kendra', 'Aberforth'}
.
V datoteki potter6.txt je besedilo šestega dela knjige Harry Potter. (V izobraževalne namene in v ne preveč lepo berljivi obliki).
Napišite funkcijo
je_stevilka_poglavja(vrstica)
, ki prejme vrstico iz datoteke in vrneTrue
, če gre za vrstico s številko poglavja. Le-te so videti tako:— CHAPTER TWENTY-ONE —
, le številka je vsakič druga.Pazi:
—
ni običajen minus. Skopiraj znak iz datoteke.Vrstici s številko poglavja vedno sledi vrstica, ki vsebujejo ime poglavja. Napiši funkcijo
imena_poglavij(ime_datoteke)
, ki prejme ime datoteke z besedilo (tako, da je reč uporabna tudi za druge knjige Harryja Potterja...) in vrne seznam imen poglavij. Seznam se začne z['The Other Minister', 'Spinner’s End', 'Will and Won’t', 'Horace Slughorn',
...
Ocena 7
Za oceno 7 se ne bo potrebno pretegniti: samo še malo bomo delali z nizi.
V besedilu se nahajajo
- številke poglavij: zazna jih funkcija
je_stevilka_poglavja
, ki jo že imamo - naslovi poglavij: to so vrstice takoj za vrstico s številko poglavja
številke strani: te se začnejo ali končajo s številko, in vse besedilo je napisano s SAMIMI VELIKIMI ČRKAMI.
Primera vrstice s številko strani sta
" WILL AND WON'T 11
in"44 HARRY POTTER"
.Vrstici
SCRIMGEOUR SUCCEEDS FUDGE
in"5 miles’. The "
nista vrstici s številko. Prva nima številke, druga ni zapisana s samimi veliki črkami.
Napiši funkcijo besedilo(ime_datoteke)
, ki prebere besedilo iz datoteke in ga vrne kot niz, ki vsebuje samo besedilo, brez številk in naslovov poglavij ter številk strani.
Za lažje testiranje bodo testi uporabljali izvleček besedila, potter6-zacetek.txt.
Ocena 8
Za oceno 8 bo potrebno brati json s spleta in ga razvozlati. Programiranja ne bo veliko, poudarek bo na tem, da znamo razumeti podatke, ki jih dobimo.
Podatke o osebah sem pridobil s fantastičnega vira, ki ima podatke o vsem na svetu - s Wikidata, ki je, v bistvu, Wikipedia v strojno berljivi obliki. Z njim je žal nekoliko nerodno delati. V domači nalogi boste okusili nekoliko tega. (Tema domače naloge so sicer osebe iz otroške literature; podobne reči bi lahko delali tudi z resnimi podatki!)
V brskalnik vnesite kakega izmed URL-jev v datoteki osebe.csv (lahko recimo, kliknete na tole: http://www.wikidata.org/entity/Q712548). Dobili boste stran iz podatkovne baze, ki vsebuje podatke o imenu te osebe v različnih jezikih, njegovih sorodnikih, spolu, datumu in kraju smrti... V nalogi za oceno 8 boste brali te podatke.
Opazite lahko, da vas je brskalnik preusmeril s strani, ki ste jo vpisali, npr. http://www.wikidata.org/entity/Q712548
na stran, ki pokaže podatke v človeku berljivi obliki https://www.wikidata.org/wiki/Q712548
. Za začetek poberite vsebino strani http://www.wikidata.org/entity/Q712548
v Pythonu, tako kot smo se učili na predavanju. Ker gre za json, ga ustrezno dekodirajte, kot smo se tudi učili. (Pazi: program mora uporabiti URL, ki vsebuje entity
in ne wiki
.)
Videli boste, da ste dobili nek grozljiv slovar. Recimo, da ga shranite v spremenljivko z imenom podatki
. Da ga lahko preberete, poskusite tole:
import pprint
pprint.pp(podatki)
Najprej nekaj o Wikidata. Vsaka stvar ("entiteta") ima "identifier". Q712548 je identifier Albusa Dumbledora, Q437 je mesto Ljubljana, Q34660 je J. K. Rowling, Q11518 je Pitagorov izrek. Kdo ali kaj je Q42, uganite.
Vsaka entiteta je opisana z lastnostmi (property). P1559 je full name -- pač za stvari, ki imajo full name; osebe ga imajo, Pitagorov izrek pač ne. P569 je dan rojstva, P21 je spol, P37 je uradni jezik, P625 so zemljepisne koordinate (Ljubljane, ne Pitagorovega izreka ali Albusa Dumbledora).
Pridobljeni slovar bo imel vedno en sem ključ entities
; pripadajoča vrednost bo imela en sam ključ, namreč oznako entitete (na primer Q712548
). Podatki so znotraj tega. Preglejte in se znajdite.
Najbolj zanimive stvari so znotraj claims
. Ključi so lastnosti, vrednosti pa so ... te lastnosti zapisani v obliki, ki jo boste videli iz pprint
-a.
Napiši funkcijo
datum_rojstva_q(identifier)
, ki prejme oznako osebe in vrne terko z letom, mesecem in dnevom, na katerega je bila rojena ta oseba.Klic
datum_rojstva_q("Q34660")
vrne(1965, 7, 31)
, ker je bila J. K. Rowling rojena 31. julija 1965.Klic
datum_rojstva_q("Q1031")
vrne(1800, 12, 3)
, ko je bil rojen pesnik.Pomoč: poišči funkcijo
strptime
in poglej dokumentacijo. Datum na Wikidata je v obliki"+%Y-%m-%dT%H:%M:%SZ"
.Napiši funkcijo
datum_rojstva(ime)
, ki prejme ime osebe iz Harryja Potterja in vrne datum rojstva te fiktivne osebe.Klic
datum_rojstva("Harry Potter")
vrne(1980, 7, 31)
, ker je bil Harry Potter rojen 31. julija 1980.Napiši funkcijo
prevod_imena(ime)
, ki bo za podano ime povedal, kaj je iz tega imena naredil slovenski prevajalec. Klicprevod_imena("Severus Snape")
vrne "Robaus Raws".(Rant: slovenskega prevoda nisem bral. Pogled na Wikipedijo pa pokaže, da se je izgleda samo slovenskemu in madžarskem prevajalcu zdelo potrebno zamenjati originalna imena z nekimi svojimi slaboumotvori.)
Da bo vaš program tekel hitreje, je testom priložena moja funkcija urlopen
. Namesto da bi uvažali urlopen
iz urllib.request
, temveč kličite to, mojo funkcijo. Ta bo brala vnaprej pobrane podatke iz priložene datoteke osebe.json, pravo funkcijo urlopen
pa poklicala le za podatke, ki jih ni v datoteki.
Ocena 9
Naloga za oceno 9 nas bo še malo vadila v igranju s slovarji, množicami in nizi. Predvsem bo treba razmisliti, kako se lotiti dela, da stvari ne bodo prepočasne.
Najprej bomo zamenjali imena in priimke vseh oseb z njihovimi imeni. V knjigi ima namreč veliko oseb lahko isti priimek, imena pa so (skoraj) unikatna. Napisati bo potrebno funkcijo, ki takole spreminja besedila.
po_imenih("Harry, Ron and Ginny Weasley, and also Dursley, Ollivander and Rosmerta walk'd down the corridor.")
vrne"Harry Ron and Ginny and also Vernon Garrick and Rosmerta walk'd down the corridor"
,po_imenih("Whether you call him Albus Dumbledore, or Albus Percival Wulfric Brian Dumbledore, or just Dumbledore, he was a great wizard.")
vrne"Whether you call him Albus or Albus or just Albus he was a great wizard"
po_imenih("Dumbledore was a brother of Aberforth Dumbledore and Ariana.")
vrne"Albus was a brother of Aberforth and Ariana"
po_imenih("The Potters and the Dursleys were neighbours.")
vrne isto besedilo, le brez pike na koncu.po_imenih("Justin Finch-Fletchley said: 'Don't talk to me like this - Potter!'")
vrne"Justin said Don't talk to me like this Harry"
Tudi rezultat klica z
"Finch-Fletchley said: 'Don't talk to me like this - Potter!'"
in"Finch-Fletchley said: 'Don't talk to me like this - Potter!'"
Funkcija mora izvesti naslednje operacije:
- V besedilu mora ohraniti le besede. Besede so zaporedja, ki vsebujejo vsaj eno črko, poleg tega pa lahko vsebujejo znaka
-
in'
, ki pa se morata pojaviti znotraj besede. S tem se ne zafrkavaj sam(a): testom je priložena funkcijasamo_besede(s)
, ki prejme besedilo in vrne niz, ki vsebuje le besede. Samo pokliči jo. - V besedilu zamenja vse pojavitve imena in priimka z imenom. "Harry Potter" zamenja s "Harry", "Ginny Weasley" z "Ginny". Če ima oseba več imen, zamenja popolno različico in različico z enim samim imenom: "Albus Dumbledore" zamenja z "Albus", pa tudi "Albus Percival Wulfric Brian Dumbledore" zamenja z "Albus".
- Nato (in šele nato!) zamenja vse priimke z imeni. "Potter" zamenja s "Harry", "Weasley" zamenja z "Ron", "Dumbledore" zamenja z "Albus". Kadar je priimek unikaten, je stvar jasna: "Granger" je lahko samo "Hermione". Kadar ima isti priimek več oseb, pa slovar
primarna
, ki je priložen testom, pove, katero ime je potrebno uporabiti: ključi slovarja so priimki, vrednosti pa "privzeto ime" za ta priimek. (Izbira je seveda moja, po občutku; Dursley je ponavadi Vernon in ne Dudley, recimo.)
Pomemben namig: Uporabljaj replace
! Če boš delal zanko čez besede, bo funkcija veliko prepočasna, saj je besed 932130.
Malo zavozlan namig: tako besedilu kot temu, kar zamenjuješ kot temu, s čimer zamenjuješ, na začetek in konec prištej presledek. Tako se izogneš nevarnosti, da zamenjaš del besede.
Poleg tega napiši še funkcijo
omembe(ime, besedilo)
vrne indekse mest, na katerih se pojavi podano ime v besedilu, kakršnega vrne funkcijapo_imenih
.Vzemimo niz
s = "Albus Dumbledore saw how Potter walked away with Ron Weasley, and Harry was saying something")
. Funkcijapo_imenih(s)
bi zanj vrnila"Albus saw how Harry walked away with Ron and Harry was saying something"
. Zato klicomembe("Albus", s)
vrne[0]
, klicomembe("Harry", s)
vrne[6, 12]
, klicomembe("Ron", s)
vrne[10]
.Očitno bo tvoja funkcija najprej poklicala funkcijo
po_imenih
...
Ocena 10
Za oceno 10 pa še malo numpyja.
- Napiši funkcijo
po_blokih(imena, besedilo, velikost_bloka)
, ki prejme seznam imen, besedilo knjige (npr. celotno vsebino datoteke potter6) in velikost bloka.
Besedilo obravnavamo v obliki, v kakršnega ga spremeni funkcija po_imenih
(vsebuje samo osebe, vse osebe so predstavljene samo z imeni). Besedilo gledamo v blokih, ki vsebujejo toliko besed, kot določa velikost_bloka
. Če je velikost_bloka
enaka 10000, gledamo po 10000 besed skupaj. Če zadnji blok ni poln (in najbrž ni), ga ignoriramo.
Funkcija vrne numpy
-jevo tabelo, ki ima toliko vrstic, kolikor je blokov in toliko stolpcev, kolikor je imen. Element na mestu [i, j] pove, kolikokrat se j-to ime pojavi v i-tem bloku.
V teste je dodana koda, ki bo, če imaš matplotlib in vse drugo, kar je treba, izrisala toplotni zemljevid pojavitev.
Bralci naj se spomnijo poteka zgodbe...
Za konec napiši še funkcijo
sovpadanje(besedilo, ime1, ime2, sirina)
. Tudi ta prejme besedilo knjige in ga spusti čez funkcijopo_imenih
. Nato izračuna "prekrivanje" med osebama po naslednjem postopku. Recimo, da pokličemosovpadanje(besedilo, "Ginny", "Romilda", 20)
.- Recimo, da se "Ginny" pojavi na indeksih 100, 110, 180, in 250. Tedaj bomo rekli, da Ginny, "pokriva" mesta od 80 do 120 (vključno!), od 90 do 130, od 160 do 200 in od 230 do 270 -- torej besedo, na kateri se pojavi in še 20 besed levo in desno, ker smo 20 podali kot argument
sirina
. Ker istega mesta ne pokriva dvakrat, bi bilo prav reči, da pokriva 80 do 130, 160 do 200 in 230 do 270. - Recimo, da se "Romilda" pojave na indeksih 5, 70 in 255. Potem pokriva -15 do 25, 50 do 90 in 235 do 275.
Prekrivanje med njima je potem od 80 do 90 in od 235 do 270. Velikost prekrivanje je 11 + 36 = 47. To je rezultat, ki ga mora vrniti funkcija.
Za preprostejši primer vzemimo klic
sovpadanje("Harry and Ron met Romilda and Romilda asked Harry about Ron", ime1, ime2, 2)
- Recimo, da se "Ginny" pojavi na indeksih 100, 110, 180, in 250. Tedaj bomo rekli, da Ginny, "pokriva" mesta od 80 do 120 (vključno!), od 90 do 130, od 160 do 200 in od 230 do 270 -- torej besedo, na kateri se pojavi in še 20 besed levo in desno, ker smo 20 podali kot argument
Spodnja slika kaže, katera mesta pokriva katera beseda (mesta so lahko tudi po koncu besedila ali pred začetkom!).
Harry and Ron met Romilda and Romilda asked Harry about Ron
Harry: X X X X X X X X X X
Ron: X X X X X X X X X X
Romilda: X X X X X X X
Prekrivanje med Harry in Ron je 6 (kolikor je istoležnih indeksov v prvi in drugi vrstici), prekrivanje med Harry in Romilda (prva in zadnja vrstica) je 4, prekrivanje med Ron in Romilda pa prav tako 4.
Če zmanjšamo širino na 1,
Harry and Ron met Romilda and Romilda asked Harry about Ron
Harry: X X X X X X
Ron: X X X X X X
Romilda: X X X X X
je prekrivanje med Harry in Ron je 2, med ostalima paroma pa 1.
Testi
- 12 January 2025, 5:50 PM