Laboration 7: Eget program
I laboration 7 kommer ni att skapa ett program från grunden och sedan implementera programmet i kod. Instruktionerna kommer endast beskriva de krav som ställs på programmet. Hur ni uppfyller dessa krav är upp till er.
Del 0: SMoL Tutor (enskilt)
I samband med Laboration 5-7 skall ni individuellt göra övningarna i SMoL Tutor som ni finner här. SMoL Tutor är ett system för att öva på att läsa och förstå kod samt för hjälpa er att bygga upp en mental modell över vad som händer under ytan när Python-kod körs. Övningarna tar i genomsnitt 10-20 minuter vardera och ingen enskild övning bör ta mer än 30 minuter att genomföra.
Verktyget är tillgängligt på engelska och era fullt anonymiserade svar kan komma att användas i kursutvecklingssyfte. Era anonymiserade svar kan eventuellt också komma att användas i forskningssyfte, om ni inte vill att era svar ska kunna användas i forskningssyfte så kontakta examinator. Övningarna är obligatoriska att genomföra, men det är inte tänkt att ni ska arbeta med dem under schemalagd labbtid då ni istället förväntas arbeta tillsammans med er labbpartner på de gemensamma delarna av labben.
Övningarna är:
- Definitions
- More definitions
- Even more definitions
- Mutable arrays
- More mutable arrays
- Even more mutable arrays
- Mutable variables
- More mutable variables
- Functions as values
- More about functions as values
- Lambda expressions
Ni kan göra övningarna när som helst under VT2, men i Webreg rapporteras de i grupper 1-4, 5-8 och 9-11 som är rekommenderat att göra i samband med Laboration 5, 6 respektive 7.
I samband med Laboration 7 bör ni göra färdigt de delar av SMoL Tutor som ni inte hunnit igenom tidigare.
Del 1: Rättstavning
Redovisning och kompletteringar
- Information om den muntliga redovisningen, samt eventuella kompletteringar kan ni läsa om sidan Redovisning.
Checklista att gå igenom vid redovisning
Vid redovisning ska ni gå igenom nedanstående checklista för den assistent ni redovisar för.
- Visa att ni kan köra ert program:
- Demonstrera att det går att använda med olika ordfrekvensdatafiler och att ni kan kontrollera olika texter.
- Peka ut och visa att alla krav på utskrifter och innehåll i rapporterna finns med.
- Visa att
pycodestyle
ochpydocstyle
inte ger några anmärkningar. - Den assistent som ni redovisar för kommer att be er redogöra för en eller
fler av följande moment i ert program:
- Översiktlig genomgång inläsning av ordfrekvensdata
- Översiktlig genomgång av flöde vid utskrift av rapport - vilka instanser är inblandade
- Hur upptäcks ett okänt ord, vilka instanser är inblandade i den processen?
- Hur plockas förslag på “rättstavade” ord fram?
- Vad tar/tog lång tid i er kod? Varför? Har ni lyckats få det att gå snabbare? Eller om inget tar lång tid, vad skulle kunna tänkas ta lång tid ett program som detta?
- Koden ska följa PEP 8.
- Moduler (själva filen), funktioner, klasser och metoder ska kommenteras enligt PEP 257.
- Koden ska följa koddispositionen nedan.
- Koden ska utföra uppgifterna enligt respektive uppgiftsbeskrivning.
- Koden ska vara uppdelad i olika filer enligt instruktionerna för respektive uppgift.
För hjälp med kontroll av PEP, se PEP 8 och PEP 257.
Krav på koddisposition
För att göra det lättare att hitta i koden är det bör den följa en genomtänkt koddisposition. Nedan är en vanlig disposition som används i många språk.
- Alla import-satser placeras högst upp i filen (se också PEP8 - Imports för intern ordning)
- Eventuella globala konstanter
- Funktionsdefinitioner
- Kod utanför funktioner, t.ex. anrop till en
main()
-funktion och annan kod iif __name__ == "__main__":
-block.
Krav på kommentarer och namngivning av funktioner och variabler
- Alla satser som består av fler än en rad ska ha en tillhörande kommentar. Dvs
if
-satser, loopar, funktioner och metoder. Kommentaren ska inte vara en “innantilläsning” av koden den hör till. Använd rätt kommentarsmarkering (d.v.s.#
för kommentarer i löpande kod, se PEP8 - Comments, och"""
för dokumentationssträngar, PEP 257). - Funktioner och variabler ska vara döpta på ett bra sätt, dvs att de är beskrivande och reflekterar innehåll/funktion. Låt funktionsnamn vara verb och variabelnamn vara substantiv. Undvik namn på enbart en bokstav (var beredda att kunna motivera varför ni valt just det namnet). Se PEP8 - Naming Conventions för mer detaljer.
Här är icke-godkänd kod:
|
|
Här är en godkänd variant:
|
|
Annat att tänka på
- Minimera användningen av hårdkodade siffror, (s.k. magic numbers). Använd istället variabler med förklarande namn.
- Dela upp er kod i delfunktioner/delmetoder vid behov:
- när ni stöter på kod som ni upprepar, bryt ut koden (lägg koden i en separat funktion/metod)
- dela även upp er kod i fler funktioner/metoder när den blir för lång
Uppgift
I denna uppgift ska ni skriva ett program som kontrollerar stavning på alla ord i en fil. Stavningskontrollen ska använda ordfrekvensdata för att kontrollera orden. I de fall där ett ord inte finns med bland ordfrekvens-data (dvs att ordet är okänt för programmet), ska förslag på rättstavning visas.
Denna laboration blir lite av en fortsättning på laboration 2 i kursen. I
laboration 2 använde ni ordfrekvensdata för att föreslå möjliga fortsättningar
på ett ord användaren skrev in, t.ex. "hopps"
-> "hoppsan"
.
I denna uppgift ska ni beräkna det kortaste redigeringsavståndet (minimum edit distance) mellan okända ord ni stöter på i en text och ord som finns bland ordfrekvens-datat. För varje okänt ord ska programmet ge förslag på kända ord som skulle kunna ersätta det okända ordet med.
Programmet ska också informera om hur lång tid det tar att köra, skriva ut information under körning, samt spara en rapport med förslag på ordersättningar.
Förrutom att ert program ska uppfylla kraven nedan så ska ni även se till att koden följer kodkraven.
Se vidare avsnitten nedan om
- Förberedelser innan ni börjar implementera
- Kortaste redigeringsavståndet
- Ordfrekvens-data
- Texter ni kan kontrollera
- Räkna ut hur lång tid något tar
- Förslag på kända ord
- Modulen argparse (frivilligt)
Förberedelser innan ni börjar programmera
Innan ni börjar programmera, gör nedanstående förberedelser och visa dem för en labassistent.
- Läs igenom informationen om implementationskrav m.m. (listan ovan).
- Diskutera och beskriv med egna ord vad ert program ska göra. Vad behöver ert program göra? I vilken ordning? Skriv ner detta som modulkommentar i er skriptfil.
- Utöver
Report
ochSpellingWarning
, som beskrivs nedan, vilka klasser behöver ni? Skissa ett UML-diagram och kom ihåg att uppdatera det om ni ändrar er design. - Beskriv kortfattat i text vad olika klasser ska göra. Detta är dels för att ni i pargruppen ska vara överrens om hur ni vill strukturera programmet, samt för att underlätta för labassistenterna när de hjälper er och vid redovisning. Skriv beskrivningar av era klasser i er skriptfil som docstrings till de klasser som ni har beskrivit i ert UML-diagram.
UML-diagram
Ett första klassdiagram för er kod skall stämmas av med assistent innan ni börjar skriva kod. Detta skall uppdateras om ni vid implementationen lägger till eller ändrar i er design.
Om ni skissat ert initiala klassdiagram på papper är det rekommenderat att använda ett program eller webbtjänst för att rita upp klassdiagrammet. På så sätt kan man enkelt uppdatera sitt klassdiagram.
- På datorerna i SU-salarna och på ThinLinc finns programmet Umbrello installerat (under kategorin “Development”)
- Gratis webbtjänster ni kan använda: draw.io, umletino
Krav på implementationen
Ni får definiera fler klasser än de som beskrivs nedan. Ni får också skriva ut mer information utöver det som anges nedan.
Körtid: Ert program får inte ta mer än 1 minut per körning på datorerna i labbsalen (alt. via Remote SSH).
Se tipsen nedan för saker ni kan tänka på för att minska körtiden.
Klasser
- Koden ska definiera klassen
SpellingWarning
vars instanser representerar upptäckta eventuella stavfel (bara för att ett ord inte finns i ordfrekvensdatat betyder inte att det är fel). - Koden ska definiera klassen
Report
som innehåller allaSpellingWarning
-instanser som skapas under rättstavningskontrollen.
Spara rapport i textfil
Efter att ha kontrollerat en textfil ska en rapport sparas som en textfil (en rapportfil för varje fil som kontrolleras). Rapporten ska innehålla följande:
- namnet på filen som kontrollerats
- hur lång tid det tagit att kontrollera filen
- alla potentiella fel som upptäckts
För varje potentiellt fel som upptäckts ska följande information finnas:
- radnummer som felet upptäckts på
- det potentiellt felstavade ordet
- minst tre förslag på korrekta ord
Utskrifter vid körning
När skriptet körs ska minst följande information skrivas ut:
- Efter att ordfrekvensdata har laddats, skriv ut information hur många ord som det laddats in frekvenser för, samt från vilken fil som informationen laddats in ifrån.
- När programmet börjar kontrollera en text, skriv namnet på filen som kontrolleras.
- När rapporten sparas, skriv namnet på den fil som rapporten sparats i.
Köra skriptet
Skriptet ska gå kunna anropas direkt från prompten i ett terminalfönster och ska kunna ta emot en eller fler filer att kontrollera (se exempel längre ner)
$ ./spellcheck.py ordfrekvensdata.tsv filattkontrollera.txt
Frivilligt - använd modulen argparse
Använd modulen argparse
för att hantera flaggor och argument till skriptet (se
nedan).
Exempel på anrop från terminal
Ni bestämmer själva vad som skrivs ut när ni kör ert program. Under utvecklingen kan ni också skriva ut mer information som hjälper er felsöka.
Exempel på kontroll av texten kort2.txt
och 6cyyy-2019.txt
med hjälp av
ordfrekvensdata från webbnyheter:
$ ./spellcheck.py data/webbnyheter2013_stats.tsv texter/kort2.txt texter/6cyyy-2019.txt
* Loading word frequency data from 'data/webbnyheter2013_stats.tsv'...
* Frequency data for 472,748 words loaded.
* 2 file(s) to check.
* Reading 'texter/kort2.txt'' and looking for unknown words...
* Found 7 unknown words.
* Saving report to kort2_report.txt
* Reading 'texter/6cyyy-2019.txt' and looking for unknown words...
* Found 9 unknown words.
* Saving report to 6cyyy-2019_report.txt
Utskrift av rapporten för kontrollen av texten kort2.txt
:
$ cat kort2_report.txt
Spell check for 'texter/dev/kort2.txt' took 2.08 seconds.
[line 2] högga: höga, högre, hög
[line 2] tråts: trots, från, två
[line 4] totalförstörelse: totalförstördes, totalförsvarets, spelförståelse
[line 6] säjer: säger, det, som
[line 7] gallet: fallet, allt, gäller
[line 9] huvudtornen: huvudrollen, huvudstaden, huvudpersonen
[line 10] redda: rädda, redan, enda
[line 11] klocktornen: koncernen, flickorna, konkursen
[line 14] uppeges: uppges, uppger, precis
[line 16] visadee: visade, visar, vidare
[line 17] himle: himlen, ville, timme
Utskrift av rapporten för kontrollen av texten 6cyyy-2019.txt
:
$ cat 6cyyy-2019_report.txt
Spell check for for 'texter/6cyyy-2019.txt' took 1.75 seconds
[line 1] civilingenjörsprogram: civilingenjörsstudent, viktminskningsprogram, privatiseringsprogram
[line 14] matematikgrund: matchavgörande, stigmatisering, hatbrottsgrupp
[line 17] masterprofiler: batteriproblem, ministerposter, rasprofilering
[line 20] ämnesmässig: spelmässigt, skilsmässan, skilsmässor
[line 26] masterprofiler: batteriproblem, ministerposter, rasprofilering
[line 45] teoritung: teoretisk, searching, retoriken
[line 66] biofysiker: analytiker, historiker, biografier
[line 82] kvalitetsingenjör: kvalitetsansvarig, kvalitetsmärkning, kvalitetskontroll
[line 84] sensorfusion: konstruktion, konstitution, pansarfordon
Implementationstips
- Upprepa inte tidskrävande operationer i onödan: T.ex. tar det förhållandevis lång tid att läsa in en fil, så se till att ni bara läser in ordfrekvensdata och text att analysera en gång.
- Leta efter okända ord: Ta bort skiljetecken från slutet på ord för att inte de ska uppfattas som en del av ordet. Gör även om det ord ni letar efter så att det bara består av små bokstäver.
- Inläsning av ordfrekvensdata: Strunta i ord i ordfrekvensdatat som inte bara består av bokstäver.
- Kontrollera om alla tecken är bokstäver: Strängmetoden
str.isalpha()
returnerarTrue
om alla tecken i en sträng är bokstäver. - Leta efter förslag: Ni kan behöva begränsa antalet förslag ert program
letar efter för att hålla körtiden rimlig. Säg att ni letar efter förslag till
ordet “exempfl” (7 bokstäver), så finns det i
webbnyheter2013_stats.tsv
fler än 35000 möjliga ord att välja mellan. Det är därför rimligt att begränsa antalet ord som programmet tittar på. Prova t.ex. att endast räkna ut redigeringsavståndet för de 1000 mest frekventa orden (antalet är godtyckligt och syftet är endast att få ner tiden det tar för ert program att köra) - Använd dictionary: För att snabba upp uppslag av ordfrekvensen för ett ord, kan ni lagra dem i ett dictionary där ordet är nyckel och frekvensen är värdet.
- Dela upp datat: Ni kan samtidigt lagra ord-data i separata listor för olika ordlängder så slipper ni leta efter dessa vid varje sökning. Eftersom ni inte vet hur många ordlängder ni behöver kan ni skapa dessa vid behov och spara dem i ett dictionary där nyckeln är en ordlängd och värdet är en samling med ord av den längden.
- Utskrift med
print()
som inte syns på en gång: Om ni i en loop gör en utskrift, t.ex.print(value)
som inte syns förrän efter loopen är färdig kan ni lägga till nyckelordsargumentetflush=True
, dvsprint(value, flush=True)
vilket ser till att utskriften inte buffras, utan skrivs ut på en gång.
Uppgiftsinformation
Kortaste redigeringsavståndet
Det kortaste redigeringsavståndet mellan två ord är det minsta antalet operationer (t.ex. byt ut, lägg till, ta bort) som måste utföras för att förändra ett ord till ett annat.
En algoritm som beräknar detta
(Levenshtein avståndet)
finns implementerat som funkionen minimum_edit_distance
i filen
/courses/TDDE44/kursmaterial/laboration7/med.py
som ni kan kopiera och
importera in i er kod.
Väldigt frivilligt
Det kan vara roligt för den erfarne att implementera om minimum_edit_distance
i något annat, snabbare, språk, t.ex. C, C++, Rust, Zig, Fortran, Perl, etc. Vi ger dock ingen support för detta eller hur man sedan kan anropa koden från Python. Tidskravet, resultat på under en minut på universitetets datorer, skall uppfyllas även när Python-implementationen ovan används.
Ordfrekvensdata
Till denna laboration har ni möjlighet att välja mellan ordfrekvensdata som
skapats från olika källor. Datat i dessa filer är tab-separerat (dvs
tab-tecknet, \t
, används för att separera ord och dess frekvens) och sorterat
så att de mest frekventa orden kommer först. Ordfrekvenserna bygger på ordformer
och inte orden i grundform, dvs att “stor” och “stora” räknas som två olika ord.
Däremot har det inte gjorts någon skillnad på användning av stora eller små
bokstäver. Filerna finns i /courses/TDDE44/kursmaterial/laboration7/data
.
attasidor_stats.tsv
bygger på nyhetsartiklar från den lättlästa webbplatsen 8 sidor och täcker knappt 56 000 ordgp2013_stats.tsv
bygger på texter från Göteborgs-Posten från 2013 och täcker ca 386000 ordgp2d_stats.tsv
bygger på texter från Göteborgs-Postens helgbilaga och täcker drygt 85000 ordsuc3_stats.tsv
bygger på SUC 3.0 (Stockholm-Umeå Corpus) och täcker ca 95000 ordwebbnyheter2013_stats.tsv
bygger på nyhetstexter från olika webbsidor från 2013 och täcker ca 473000 ord
Det spelar ingen större roll vilken datakälla ni använder i denna laboration,
men det kommer att påverka hur många ord som är kända/okända och hur många
förslag som kan hittas (t.ex. finns det fler än 42000 ord av längden 10 i
webbnyheter2013_stats.tsv
).
Att det finns så här mycket data betyder att ni kan behöva begränsa t.ex. hur många ord ni slår upp redigeringsavståndet för för att programmet inte ska ta för lång tid på sig.
Texter att kontrollera
Ni kan använda vilka texter ni vill för att testa ert skript, men det finns
några förberedda i /courses/TDDE44/kursmaterial/laboration7/texter
. Filerna
kort2.txt
, mellan2.txt
och lang2.txt
innehåller diverse stavfel. Filerna
kort1.txt
, mellan1.txt
och lang1.txt
är de ursprungliga texterna.
Räkna hur lång tid något tar
För denna laboration kan ni använda funktionen time()
i modulen time
för att ta reda på hur lång tid som gått. Importera time
och så kan ni använda time.time()
som returnerar tiden just nu uttryckt som antalet sekunder sedan kl. 0.00, 1 januari, 1970. Spara värdet på time.time()
när ni börjar er bearbetning och spara värdet på time.time()
när ni är klara så är differensen antalet sekunder som gått.
Kuriosa: Unix Tick Tocks to a Billion
Rättstavning / förslag på kända ord
Det finns många strategier som kan tillämpas när det kommer till att ta fram förslag på vilket känt ord (ett ord som finns i ordfrekvensdatat) som ett okänt ord (ord i texten som inte finns med i ordfrekvensdatat) kan ersättas med.
Börja med att endast titta på kända ord som är av samma längd som det okända
ordet. Dvs att programmet kan föreslå korrigering av ordet "hejsam"
till
"hejsan"
.
I mån av tid kan ni uttöka funktionaliteten på programmet så att programmet även
kan föreslå korrigeringar som innebär att lägga till/ta bort bokstäver från det
okända ordet. T.ex. kan föreslå korrigering av "hejsa"
till "hejsan"
och
"hejsann"
till "hejsan"
.
Frivilligt: använda modulen argparse
Python har en inbyggd modul som kan användas för att hantera flaggor och argument som skickas till ett skript. För att lära dig om modulen, leta efter en tutorial på webben, eller se någon av de nedanstående:
- Python HOWTOs: Argparse Tutorial
- Python for Beginners: Argparse Tutorial
- Fullständig dokumentation till argparse
I laboration 7 kan argparse användas för att definiera flaggor för att från kommandoraden bestämma t.ex.
- hur många förslag som ska tas med i rapporten
- maximala antalet förslag att räkna ut minimum edit distance på
- om rapporten ska skrivas ut i terminalen förrutom att sparas till fil
- vilken datafil som ska användas
- osv.
Exempel:
$ ./spellcheck.py --data data/datafil.tsv --num_sug 5 --print-report texter/kort1.txt
Sidansvarig: Johan Falkenjack
Senast uppdaterad: 2025-05-02