L?sningsforslag ukeoppg. 5: 22. - 25. sep (INF1000 - H?st 2008)
Filer (kap. 3.5 - 3.7; 3.10 - 3.11); og tekst (kap. 6.1 - 6.9)NB! Disse er bare forslag til l?sninger, dine svar kan v?re like gode eller bedre selv om de ikke ligner p? dem.Du f?r sannsynligvis mer utbytte av l?sningsforslagene etter at du har fors?kt ? l?se oppgaven selv. Du kan ogs? finne l?sning p? noen av disse oppgavene i l?rebokens hjemmeside: www.universitetsforlaget.no/java.
M?l
F? ?velse i innlesing og utskrift til fil, og bruk av tekststrenger.
Oppgaver til teoritimen
- Innlesing og utskrift til fil:
(eksempel side 50 i l?reboka)
(a) Ta utgangspunkt i f?lgende program, fra side 50 i l?reboka, som skriver fire typer verdier til skjerm (tegn, linje, heltall, og desimaltall), og endre programmet slik at utskriften g?r til en fil i stedet. Kall utfilen "minfil.txt".import easyIO.*; class Utskrift { public static void main(String[] args) { Out skjerm = new Out(); skjerm.outln('A'); skjerm.outln("Canis familiaris betyr hund"); skjerm.outln(15); skjerm.outln(3.1415, 2); // Bruk to desimaler } }
Hint: Utskrift til fil vha. easyIO programmeres p? samme m?te som utskrift til skjerm, bare at man i tillegg angir filnavnet ? f.eks. new Out("minfil.txt"), ? og lukker filen til slutt (utfil.close()). Navnet p? forbindelsen skjerm b?r ogs? endres for ? gj?re det tydelig at man skriver til en utfil.import easyIO.*; class Utskrift { public static void main(String[] args) { Out utfil = new Out("minfil.txt"); utfil.outln('A'); utfil.outln("Canis familiaris betyr hund"); utfil.outln(15); utfil.outln(3.1415, 2); // Bruk to desimaler utfil.close(); } } KJ?REEKSEMPEL: > more minfil.txt A Canis familiaris betyr hund 15 3.14
(b) Utvid programmet slik at det ogs? leser innholdet i filen som ble opprettet i del (a), lagrer det i fire passende variabler (den f?rste skal v?re av typen char, osv.), og skriver til slutt verdiene i variablene ut p? skjerm.Hint: Innlesing fra fil programmeres som innlesing fra tastatur, men man m? i tillegg angi filnanvet ? f.eks. new In("minfil.txt").import easyIO.*; class Utskrift { public static void main(String[] args) { Out skjerm = new Out(); Out utfil = new Out("minfil.txt"); utfil.outln('A'); utfil.outln("Canis familiaris betyr hund"); utfil.outln(15); utfil.outln(3.1415, 2); // Bruk to desimaler utfil.close(); skjerm.outln(" Fil 'minfil.txt' opprettet med 4 verdier."); In innfil = new In("minfil.txt"); char tegn = innfil.inChar(); String linje = innfil.inLine(); int heltall = innfil.inInt(); double flyttall = innfil.inDouble(); innfil.close(); skjerm.outln(" Leste f?lgende verdier fra filen 'minfil.txt':"); skjerm.outln(tegn); skjerm.outln(linje); skjerm.outln(heltall); skjerm.outln(flyttall); } } KJ?REEKSEMPEL: > java Utskrift Fil 'minfil.txt' opprettet med 4 verdier. Leste f?lgende verdier fra filen 'minfil.txt': A Canis familiaris betyr hund 15 3.14
- Lese/skrive en fil tegn for tegn:
(side 54 i l?reboka, og lysark uke 5)
(a) Lag et program som leser inn en fil og kopierer innholdet over til en annen fil. Filen skal leses inn et tegn av gangen vha. inChar(). Du kan ta utgangspunkt i programmet vist under, fra side 54 i l?reboka (og side 8 i lysarkene for uke 5), som leser en fil et tegn av gangen, men skriver innholdet i filen ut p? skjermen (i stedet for til en annen, nyopprettet fil). Endre klassenavnet til Kopi, og utvid programmet slik at det ber bruker taste inn filnavnene for de to filene (original og kopi).import easyIO.*; class Tegnleser { public static void main(String[] args) { In innfil = new In("minfil.txt"); int antall = 0; while (!innfil.endOfFile()) { char tegn = innfil.inChar(); System.out.print(tegn); antall++; } System.out.println("Antall tegn: " + antall); } }
import easyIO.*; class Kopi { public static void main(String[] args) { Out skjerm = new Out(); In tast = new In(); skjerm.out("Filnavn original: "); String innfilnavn = tast.inLine(); skjerm.out("Filnavn kopi: "); String utfilnavn = tast.inLine(); In innfil = new In(innfilnavn); Out utfil = new Out(utfilnavn); int antall = 0; while (!innfil.endOfFile()) { char tegn = innfil.inChar(); utfil.out(tegn); antall++; } innfil.close(); utfil.close(); System.out.println("Antall tegn kopiert: " + antall); } } KJ?REEKSEMPEL: > java Kopi Filnavn original: minfil.txt Filnavn kopi: minfil2.txt Antall tegn kopiert: 38
NB! Antall tegn blir 38 p? Linux (hvor linjene slutter med "\n"), og 42 p? Windows (hvor linjene slutter med "\r\n").
(b) Ta utgangspunkt i programmet vist ovenfor, og endre det slik at det skriver ut tegnene fra den innleste fil til skjerm, men med alle sm? bokstaver konvertert til store bokstaver. F?lgende setninger (fra side 27 i lysarkene for uke 5) viser hvordan man kan konvertere innholdet i en char-variabel c til store eller sm? bokstaver:char c = ’x’; char c2 = Character.toUpperCase(c); char c3 = Character.toLowerCase(c);
import easyIO.*; class StoreBokstaver { public static void main(String[] args) { In innfil = new In("minfil.txt"); int antall = 0; while (!innfil.endOfFile()) { char tegn = innfil.inChar(); tegn = Character.toUpperCase(tegn); System.out.print(tegn); antall++; } System.out.println("Antall tegn: " + antall); } } KJ?REEKSEMPEL: > java StoreBokstaver A CANIS FAMILIARIS BETYR HUND 15 3.14 Antall tegn: 38
NB! Antall tegn blir 38 p? Linux (hvor linjene slutter med "\n"), og 42 p? Windows (hvor linjene slutter med "\r\n").
(c) Lag to tellere til, en som finner ut hvor mange bokstaver filen inneholder (a-z, A-Z, osv.), og en som teller tallsifre (0-9). Skriv ut resultatet av disse to tellerne til slutt, p? samme m?te som utskriften av antall tegn vist ovenfor (alle 3 skrives til skjerm). For ? finne ut om en innlest char er et tallsiffer kan du bruke testen"if (tegn >= '0' && tegn <= '9')", og tilsvarende for bokstaver (>= 'A' og <= 'Z', osv.)import easyIO.*; class Tegnteller { public static void main(String[] args) { In innfil = new In("minfil.txt"); int antTegn = 0; int antSifre = 0; int antBokstaver = 0; while (!innfil.endOfFile()) { char tegn = innfil.inChar(); System.out.print(tegn); antTegn++; if (tegn >= '0' && tegn <= '9') { antSifre++; } tegn = Character.toUpperCase(tegn); if ((tegn >= 'A' && tegn <= 'Z') || tegn == '?' || tegn == '?' || tegn == '?') { antBokstaver++; } } System.out.println("\nAntall tegn: " + antTegn); System.out.println("Antall sifre: " + antSifre); System.out.println("Antall bokstaver: " + antBokstaver); } } KJ?REEKSEMPEL: > java Tegnteller A Canis familiaris betyr hund 15 3.14 Antall tegn: 38 Antall sifre: 5 Antall bokstaver: 25
NB! Antall tegn blir 38 p? Linux (hvor linjene slutter med "\n"), og 42 p? Windows (hvor linjene slutter med "\r\n").
- Lese/skrive en fil linje for linje:
(eksempel side 55 i l?reboka)
(a) Studér f?lgende program, fra side 55 i l?reboka, som leser en fil en linje av gangen, og skriver den ut p? skjermen med linjenummer foran i hver linje. Endre programmet slik at det i stedet for ? skrive ut alle linjene bare skriver ut en melding til slutt om hvor mange linjer og hvor mange tegn filen inneholder. For ? telle antall tegn kan du innf?re en teller-variabel til, som summerer verdiene av linje.length().import easyIO.*; class Linjeleser { public static void main(String[] args) { In innfil = new In("minfil.txt"); int linjenummer = 0; while (!innfil.endOfFile()) { String linje = innfil.readLine(); linjenummer++; System.out.println(linjenummer + " " + linje); } } }
import easyIO.*; class Linjeleser { public static void main(String[] args) { In innfil = new In("minfil.txt"); int antLinjer = 0; int antTegn = 0; while (!innfil.endOfFile()) { String linje = innfil.readLine(); antLinjer++; antTegn += linje.length() + 1; // + 1 for ? ta med linjeskiftet "\n" } System.out.println("Antall linjer: " + antLinjer); System.out.println("Antall tegn: " + antTegn); } } KJ?REEKSEMPEL: > java Linjeleser Antall linjer: 4 Antall tegn: 38
(b) Ta utgangspunkt i programmet vist ovenfor, og endre det slik at det skriver ut linjene p? skjerm, men med alle sm? bokstaver konvertert til store bokstaver. F?lgende setninger (fra side 27 i lysarkene for uke 5) viser hvordan man kan konvertere bokstavene i en String-variabel til store eller sm? bokstaver:String s = "Jeg ER 18 ?r"; String s2 = s.toUpperCase(); // N? er s2 tekststrengen "JEG ER 18 ?R"
import easyIO.*; class Linjeleser { public static void main(String[] args) { In innfil = new In("minfil.txt"); int linjenummer = 0; while (!innfil.endOfFile()) { String linje = innfil.readLine(); linje = linje.toUpperCase(); linjenummer++; System.out.println(linjenummer + " " + linje); } } } KJ?REEKSEMPLER: > java Linjeleser 1 A 2 CANIS FAMILIARIS BETYR HUND 3 15 4 3.14
(c) Endre programmet fra (a) slik at filnavnet tas fra f?rste kommandolinjeargument. "Kommandolinjeargumenter" er evt. tilleggs-ord som bruker angir i selve java-kommandolinjen n?r hun kj?rer programmet. For eksempel, hvis bruker starter programmet med f?lgende kommando:> java Linjeleser fil1.txt xyz
import easyIO.*; class Linjeleser { public static void main(String[] args) { if (args.length == 0) { System.out.print("Du m? angi et filnavn, f.eks. slik: "); System.out.println(" java Linjeleser filnavn"); System.exit(1); } In innfil = new In(args[0]); int antLinjer = 0; int antTegn = 0; while (!innfil.endOfFile()) { String linje = innfil.readLine(); antLinjer++; antTegn += linje.length(); } System.out.println("Antall linjer: " + antLinjer); System.out.println("Antall tegn: " + antTegn); } } KJ?REEKSEMPLER: > java Linjeleser minfil.txt Antall linjer: 4 Antall tegn: 34 > java Linjeleser Linjeleser.java Antall linjer: 22 Antall tegn: 525
- Lese to arrayer fra fil: Oppgave 3, kap. 5 (side 97)
Lag et program som skal behandle data om vekten til elevene i en skoleklasse. Det er 27 elever i klassen. Dataene ligger p? fil slik:Jens 52 Marit 43 ...
(b) La programmet finne h?yeste og laveste vekt og skrive ut navn og vekt p? disse.
(c) La programmet beregne gjennomsnittsvekten i klassen.
Hint: Se eksemplet p? side 60 i l?reboka under "// Fil til array". I del (c) kan du bruke gjennomsnitts-metoden fra oppgave 8. forrige uke:Metode med array som inn-parameter: Oppgave 3, kap. 7 (side 134)
Lag en metode double gjennomsnitt(int[] a) som summerer alle elementene i heltallsarrayen a, og som returnerer (det aritmetiske) gjennomsnittet av verdiene i a.import easyIO.*; class ElevVekt { public static void main(String[] args) { In innfil = new In("elevvekt.txt"); final int ANT_ELEVER = 27; String[] navn = new String[ANT_ELEVER]; int[] vekt = new int[ANT_ELEVER]; // (a): Leser dataene fra fil inn i to arrayer: for (int i = 0; i < ANT_ELEVER; i++) { navn[i] = innfil.inWord(); vekt[i] = innfil.inInt(); } // (b): Finner indeksene i arrayen der vekt er h?yest og lavest: int h?yVektIndeks = 0; int lavVektIndeks = 0; for (int i = 0; i < vekt.length; i++) { if (vekt[i] > vekt[h?yVektIndeks]) { h?yVektIndeks = i; } if (vekt[i] < vekt[lavVektIndeks]) { lavVektIndeks = i; } } System.out.println("Tyngste elev: " + navn[h?yVektIndeks] + " " + vekt[h?yVektIndeks] + " kg"); System.out.println("Letteste elev: " + navn[lavVektIndeks] + " " + vekt[lavVektIndeks] + " kg"); // (c): Gjennomsnittsvekt: ElevVekt ev = new ElevVekt(); double snitt = ev.finnGjennomsnitt(vekt); System.out.printf("Gjennomsnittsvekt: %.1f\n", snitt); } double finnGjennomsnitt(int[] a) { int sum = 0; for (int i = 0; i < a.length; i++) { sum += a[i]; } return (double) sum / a.length; } } KJ?REEKSEMPEL: Tyngste elev: Jens 53 kg Letteste elev: Anna 33 kg Gjennomsnittsvekt: 44.8
- Tekster: Hva blir skrevet ut?
Du kan lese mer om disse tekst-uttrykk i lysarkene for uke 5, side 20 - 40.import easyIO.*; class Tekster { public static void main(String[] args) { Out skjerm = new Out(); String s1 = "hei"; String s2 = "Java"; String[] navn = { "Rune", "Martin", "Guro", null }; /* a */ skjerm.outln(navn.length + s1.length());
7
/* b */ skjerm.outln(3.1415 + "" + 'x');
3.1415x
/* c */ skjerm.outln("" + false);
false
/* d */ skjerm.outln("" + ! "abc".equals("abc"));
false
/* e */ skjerm.outln("heia" == (s1 + "a"));
false
/* f */ skjerm.outln("heia".equals(s1 + s2.charAt(1)));
true
/* g */ skjerm.outln(s1.equals("h" + navn[0].charAt(3) + 'i'));
true
/* h */ skjerm.outln(navn[1].substring(1));
artin
/* i */ skjerm.outln(navn[1].substring(1, 4));
art
/* j */ skjerm.outln(s2.replace('a', 'i'));
Jivi
/* k */ skjerm.outln(navn[1].indexOf("tin"));
3
/* l */ skjerm.outln(navn[2].indexOf("tin"));
-1
/* m */ skjerm.outln("A".compareTo("A"));
0
/* n */ if (s1.compareTo("zz") < 0) skjerm.outln("s1 alfabetisk foran");
s1 alfabetisk foran
/* o */ skjerm.outln(navn[2].toUpperCase());
GURO
/* p */ if ("hei p? deg".startsWith(s1)) { skjerm.outln("ja"); }
ja
/* q */ int x = Integer.parseInt("123"); skjerm.outln(x + 1); } }
124
- Ord baklengs: Oppgave 3 (a), kap. 6 (side 115)
Lag et program som skriver ut teksten ?Agnes i senga? baklengs. Hint: Bruk en for-l?kke som teller nedover.import easyIO.*; class Baklengs { public static void main (String[] args) { Out skjerm = new Out(); String tekst = "Agnes i senga"; skjerm.out(tekst + " baklengs: "); int antallTegn = tekst.length(); for (int i = antallTegn - 1; i >= 0; i--) { skjerm.out(tekst.charAt(i)); } skjerm.outln(); } } KJ?REEKSEMPEL: > java Baklengs Agnes i senga baklengs: agnes i sengA
Oppgaver til terminaltimen
- Filer og tekster:
(De samme oppgavene som for teoritimen, punkt 1. til 4.). Kontrollér at filene blir laget riktig ved ? skrive kommandoen: more filnavn.txt p? kommandovinduet (Linux/Mac), eller: type filnavn.txt (Windows). Disse kommandoene viser n?v?rende innhold i den angitte filen.
- Lukking av filer: Oppgave 5, kap. 3 (side 71)
Programmet under er ment ? skulle skrive setningen ?En fugl i h?nden er bedre enn ti p? taket.? til en fil med navn ?ordtak.txt?, men noe mangler, slik at resultatet blir en tom fil. Finn feilen!import easyIO.*; class Ordtak { public static void main (String[] args) { Out utfil = new Out("ordtak.txt"); utfil.outln("En fugl i h?nden er bedre enn ti p? taket."); } }
Det mangler utfil.close();.
- Tallsiffer-oversetting: Oppgave 7 og 8, kap. 6 (side 116)
(a) Lag et program som oversetter fra tallsiffer til tekst slik at f.eks. 3 blir oversatt til "tre". Programmet skal kunne oversette alle 10 sifre (fra 0 til 9). Hint: Bruk en array med tekstene "null", "en", "to", osv.
(b) Lag et program som oversetter fra tekst til tall. Programmet skal be brukeren skrive inn et tall mellom null og ni (med bokstaver), og skrive ut tilsvarende siffer.import easyIO.*; class Tallsiffer { public static void main(String[] args) { Out skjerm = new Out(); In tast = new In(); String[] tallnavn = { "null", "en", "to", "tre", "fire", "fem", "seks", "sju", "?tte", "ni" }; // (a) skjerm.out("Siffer (0-9): "); int siffer = tast.inInt(); skjerm.outln("= " + tallnavn[siffer]); // (b) skjerm.out("Tallnavn (null-ni): "); String ord = tast.inWord(); for (int i = 0; i < tallnavn.length; i++) { if (ord.equals(tallnavn[i])) { skjerm.outln("= " + i); } } } } KJ?REEKSEMPEL: Siffer (0-9): 4 = fire Tallnavn (null-ni): tre = 3
- Gj?r ferdig obligatorisk oppgave 2.
- Ekstraoppgave: L?r deg metoder
Fullf?r f?lgende program, som viser bruk av metoder. Angi ogs? hva programmet skriver ut.import easyIO.*; class Metoder { public static void main(String[] args) { TestMetoder tm = new TestMetoder(); tm.start(); } } class TestMetoder { In tast = new In(); Out skjerm = new Out(); void start() { // Kaller en enkel metode: metode1(); // Kaller en metode med én inn-parameter: skrivTredoblet(123); // Leser to tall fra tastatur, og overf?rer de til en metode // som finner og skriver ut det h?yeste av de to tall: skjerm.out("Skriv to tall (f.eks. 7 4): "); int tall1 = tast.inInt(); int tall2 = tast.inInt(); finnH?yesteAv2(tall1, tall2); // Kaller en metode som multipliserer de samme to tall lest // inn ovenfor, og returnerer resultatet hit. int resultat = multipliser( /* Fyll inn resten. . . */ ); skjerm.outln("Resultat multiplisert: " + resultat); // Metode med array som inn-parameter: double[] verdier = { 0, -3, 5, 10, -20, -7.7, 1.2, -0.01 }; //int antNeg = finnAntallNegativeTall(verdier); //skjerm.outln("Arrayen verdier[] har " + antNeg + " negative tall."); // <- Ta bort "//" i de to linjene over. } void metode1() { skjerm.outln("Dette er metode1"); } void skrivTredoblet(int x) { int tredoblet = x * 3; skjerm.outln("Tredoblet resultat = " + tredoblet); } void finnH?yesteAv2(int a, int b) { // Hva mangler her? // . . . skjerm.outln("H?yest av de to tall er:" /* . . . */ ); } int multipliser( /* Fyll inn resten. . . */) { // . . . return 0 ; // . . . Erstatt 0 med resultatet av x ganger y. } // Skriv metoden "finnAntallNegativeTall" her, som har en array med // double-verdier som inn-parameter, finner ut hvor mange av verdiene // i arrayen er negative tall, og returnerer det antallet (som en int). // . . . }
import easyIO.*; class Metoder { public static void main(String[] args) { TestMetoder tm = new TestMetoder(); tm.start(); } } class TestMetoder { In tast = new In(); Out skjerm = new Out(); void start() { // Kaller en enkel metode: metode1(); // Kaller en metode med én inn-parameter: skrivTredoblet(123); // Leser to tall fra tastatur, og overf?rer de til en metode // som finner og skriver ut det h?yeste av de to tall: skjerm.out("Skriv to tall (f.eks. 7 4): "); int tall1 = tast.inInt(); int tall2 = tast.inInt(); finnH?yesteAv2(tall1, tall2); // Kaller en metode som multipliserer de samme to tall lest // inn ovenfor, og returnerer resultatet hit. int resultat = multipliser(tall1, tall2); skjerm.outln("Resultat multiplisert: " + resultat); // Metode med array som inn-parameter: double[] verdier = { 0, -3, 5, 10, -20, -7.7, 1.2, -0.01 }; int antNeg = finnAntallNegativeTall(verdier); skjerm.outln("Arrayen verdier[] har " + antNeg + " negative tall."); } void metode1() { skjerm.outln("Dette er metode1"); } void skrivTredoblet(int x) { int tredoblet = x * 3; skjerm.outln("Tredoblet resultat = " + tredoblet); } void finnH?yesteAv2(int a, int b) { int h?yeste = a; if (b > a) { h?yeste = b; } skjerm.outln("H?yest av de to tall er: " + h?yeste); } int multipliser(int a, int b) { int produkt = a * b; return produkt; } // Skriv metoden "finnAntallNegativeTall" her, som har en array med // double-verdier som inn-parameter, finner ut hvor mange av verdiene // i arrayen er negative tall, og returnerer det antallet (som en int). int finnAntallNegativeTall(double[] verdier) { int antNegative = 0; for (int i = 0; i < verdier.length; i++) { if (verdier[i] < 0) { antNegative++; } } return antNegative; } } KJ?REEKSEMPEL: > java Metoder Dette er metode1 Tredoblet resultat = 369 Skriv to tall (f.eks. 7 4): 100 55 H?yest av de to tall er: 100 Resultat multiplisert: 5500 Arrayen verdier[] har 4 negative tall.
- Ukens n?tt: Sudoku hjelpeprogram
(a) Lag et program som leser inn en Suduko-oppgave fra fil og lagrer de forh?ndsutfylte tallene i en 2-dimensjonal array. Deretter g?r programmet i en l?kke som sp?r brukeren om et rad- og et kolonnenummer (i omr?det 1-9, eller 0 for ? avslutte). Programmet skal s? svare brukeren med hvilke tall (1-9) som er mulige kandidater for plassering i den angitte rad/kolonne-plassen, ved ? finne ut hvilke av sifrene 1-9 ikke er allerede brukt i samme rad, kolonne, eller 3×3-omsluttende boks.
Input-filen er p? 9 linjer, med 9 tall per linje adskilt med mellomrom, og hvor 0 angir plassene som ikke har forh?ndsutfylt siffer i Sudoku-oppgaven. Her er et eksempel p? en slik fil (med middels vanskelig oppgave). Finn gjerne andre oppgaver fra aviser eller nettet.6 0 7 0 0 0 0 8 0 0 0 0 1 0 4 0 7 0 0 0 5 0 0 8 0 3 0 8 0 0 3 0 0 7 0 0 4 0 0 5 0 6 0 0 8 0 0 1 0 0 2 0 0 6 0 8 0 4 0 0 5 0 0 0 9 0 2 0 3 0 0 0 0 7 0 0 0 0 1 0 3
NB! Prosedyren beskrevet i n?tte-oppgaven finner bare noen l?sningssifre i typiske oppgaver, det er ikke en Sudoku-l?ser. Se oblig 3 i INF1010 for tips om en fullstendig Sudoku-l?ser. For ? kj?re f?lgende program trenger du en fil med sudoku-oppgave, f.eks.: sudoku1.txt, sudoku2.txt
L?sning med alt i main-metoden: SudokuRunarfu.java (versjon 2) Laget av Runar Furenes i gr. 8.
Hvis du kommer p? en l?sning som bruker flere metoder send den gjerne til josek@ifi.uio.no s? legger jeg den ut her. - Ukens n?tt: Sudoku hjelpeprogram