// Version 9/7/2001/OCL. package inf101; import java.io.*; import java.util.*; import java.net.*; /** Denne klassen er laget ved Ifi, UiO og inneholder metoder * for ? lese fra terminal og fil. Klassen st?tter b?de innlesing * linje for linje, tegn for tegn, og item for item (hvor et item * kan v?re et heltall, et flyttall eller en tekststreng). De tre * typene innlesing kan kombineres. * * Eksempler p? bruk: * <pre> * (1) Lese linje for linje fra fil: * * String linje; * Inn innfil = new Inn("tekstfil.txt"); * while (!innfil.endOfFile()) { * linje = innfil.inStringLn(); * ...Gj?r noe med den leste linjen... * } * * (2) Lese fil med heltall (atskilt med blanke og/eller linjeskift): * * int tall; * Inn innfil = new Inn("fil.txt"); * while (!innfil.lastItem()) { * tall = innfil.inInt(); * ...Gj?r noe med det innleste tallet... * } * </pre> * Version 9/7/2001/OCL. **/ public class Inn { private final boolean FILE; private final int NEWTRIES; private boolean EOF; private String cur=""; private BufferedReader in; private int lineNo = 0; /** Lager et Inn-objekt for lesing fra tastatur. **/ public Inn() { in = new BufferedReader(new InputStreamReader(System.in)); EOF = false; FILE = false; NEWTRIES = 3; } /** Lager et Inn-objekt for lesing fra spesifisert fil eller URL. * Dersom <CODE>name</CODE> starter med <CODE>"http://"</CODE> * tolkes <CODE>name</CODE> * som en URL (dvs som en web-adresse). I alle andre tilfeller tolkes * <CODE>name</CODE> som et filnavn (med eller uten path). Dersom det * ikke angis noen path antas det at filen ligger p? samme katalog som * Java-programmet ligger p?. En path kan enten v?re en relativ path * eller en absolutt path. En relativ path angir en katalog relativt * til katalogen som Java-programmet ligger p?, f.eks. * <pre> * ../viktigbrev.txt * obliger/Register.java * </pre> * En absolutt path angir en katalog i forhold til rotkatalogen, f.eks. * <pre> * /ifi/ganglot/k01/inf101/LES_MEG * </pre> * Merk: forel?pig kan en ikke benytte linker (slik som ~ eller /hom/) * i pathen n?r en oppretter et Inn-objekt. **/ public Inn (String name) { if (name.startsWith("http://")) { try { URL url = new URL(name); in = new BufferedReader(new InputStreamReader(url.openStream())); } catch (MalformedURLException e) {feil("Inn(String name): Feil i URL'en!");} catch (IOException e) {feil("Inn(String name): Klarte ikke ? ?pne fila!");} } else { try { in = new BufferedReader(new FileReader(name)); } catch (IOException e) {feil("Inn(String name): Klarte ikke ? ?pne fila!");} } EOF = false; FILE = true; NEWTRIES = 0; newLine(); } /** Lukker filen. **/ public void close() { try { in.close(); } catch (IOException e) {feil("close(): Klarte ikke ? lukke fila!");} } private void feil (String s) { System.out.println("\nFeil i " + s + "\n"); System.exit(0); } private void melding (String s) { System.out.println("\nAdvarsel i " + s + "\n"); } /** Returnerer true hvis EOF eller resten av linjen er tom. **/ public boolean empty() { if (EOF || cur.equals("")) return true; else return false; } /** Returnerer true hvis EOF eller resten av linjen er blanke tegn. **/ public boolean white() { if (EOF || cur.trim().equals("")) return true; else return false; } /** Les inn neste linje i buffer hvis ikke EOF. Setter EOF=true * hvis slutt p? fila oppdages **/ private void newLine() { String cur2 = null; if (!EOF) { try { cur2 = in.readLine(); } catch (IOException e) { feil("newLine(): Feil ved innlesning!"); } lineNo++; if (cur2 != null) cur = cur2; else EOF = true; } } /** Hopp fram til f?rste tegn. Hopper over eventuelle * linjeskift fram til f?rste tegn. **/ public void skipEmpty() { while (!EOF && empty()) newLine(); } /** Hopp fram til f?rste * ikke-blanke tegn. Hopper over blanke tegn (inkludert tabulatortegn) * og linjeskift. */ public void skipWhite() { while (!EOF && white()) newLine(); if (!EOF) { while (Character.isWhitespace(cur.charAt(0))) cur = cur.substring(1); } } /** Hopp helt til slutten av linjen */ public void flushLine() { cur = ""; } /** Hopp fram til f?rste tegn som er forskjellig fra de spesifiserte * separatortegnene. Dersom f.eks. <CODE>sep</CODE> er tekststrengen * <CODE>"&* "</CODE> s? vil en hoppe fram til f?rste tegn som ikke * er '&', '*' eller ' '. Kontrolltegn som starter med '\' kan ogs? * angis, f.eks. <CODE>"\t"</CODE> for ? hoppe over tabulatortegn. * For ? hoppe * over tegnet '\' m? en angi "\\". Eksempel: hvis <CODE>sep</CODE> * er tekststrengen <CODE>" \t\\"</CODE> s? vil en hoppe fram til * f?rste tegn som * ikke er ' ', tabulator-tegn eller '\'. */ public void skipSep(String sep) { StringTokenizer st = new StringTokenizer(cur, sep); while (!EOF && !st.hasMoreTokens()) { newLine(); st = new StringTokenizer(cur, sep); } if (!EOF) { String s = st.nextToken(); int i = cur.indexOf(s); cur = cur.substring(i, cur.length()); } } /** Sjekk om alle tegn (og linjeskift) er lest. Returnerer * <CODE>true</CODE> dersom alle tegn (inkludert blanke) og linjeskift * er lest, og returnerer <CODE>false</CODE> ellers. * Kun ved lesing fra fil eller URL. **/ public boolean endOfFile() { return EOF; } /** Sjekk om siste ikke-blanke tegn er lest. Hopper fram til * f?rste ikke-blanke tegn, eller til slutten av filen dersom * det bare er blanke tegn igjen. I f?rste tilfelle returneres * verdien <CODE>true</CODE> og i siste tilfelle returneres verdien * <CODE>false</CODE>. Kun ved lesing fra fil eller URL. **/ public boolean lastItem() { skipWhite(); return EOF; } /** Sjekk om siste ikke-separator tegn er lest, hvor separatortegn * er de tegn som er spesifisert med parameteren <CODE>sep</CODE>. * Dersom f.eks. <CODE>sep</CODE> er tekststrengen * <CODE>"&* "</CODE> s? er separatortegnene * '&', '*' og ' '. Kontrolltegn som starter med '\' kan ogs? * angis, f.eks. <CODE>"\t"</CODE> for tabulatortegn. * For ? angi separatortegnet '\' m? en bruke "\\". Eksempel: * hvis <CODE>sep</CODE> * er tekststrengen <CODE>" \t\\"</CODE> s? vil separatortegnene * v?re ' ', tabulator-tegn og '\'. * Hopper fram til f?rste ikke-separator tegn, eller til slutten av * filen dersom * det bare er separator-tegn igjen. I f?rste tilfelle returneres * verdien <CODE>true</CODE> og i siste tilfelle returneres verdien * <CODE>false</CODE>. Kun ved lesing fra fil eller URL. **/ public boolean lastItem(String sep) { skipSep(sep); return EOF; } /** Les et tegn. Det hoppes over eventuelle innledende linjeskift. **/ public char inChar() { char c='*'; skipEmpty(); if (!EOF) { c = cur.charAt(0); cur = cur.substring(1); } else { feil("inChar(): slutt p? filen!"); } return c; } /** Les et tegn med spesifiserte tegn som separatortegn. * Det hoppes over eventuelle innledende linjeskift og * separatortegn spesifisert i <CODE>sep</CODE>.Separatortegn angis * som en tekststreng, f.eks. "%&" for ? bruke '%' og '&' som separatortegn. **/ public char inChar(String sep) { char c='*'; skipSep(sep); if (!EOF) { c = cur.charAt(0); cur = cur.substring(1); } else { feil("inChar(): slutt p? filen!"); } return c; } /** * Les et heltall med blank som separatortegn. Det hoppes * over eventuelle innledende * blanke tegn (inkludert tabulatortegn) og linjeskift. Det gis * feilmelding dersom f?rste * ikke-blanke tegn er noe annet enn et siffer. */ public int inInt() { char c='*'; String number = ""; int i = 0; do { // Les tekst if (!lastItem()) { c = cur.charAt(0); if (c=='-') { number = "-"; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } } else { feil("inInt(): Slutt p? filen!"); } // Konverter fra tekst til tall try { return Integer.parseInt(number); } catch (NumberFormatException e) { if (FILE) { feil("inInt(): Forventet heltall i linje " + lineNo + "."); } else { melding("inInt(): Forventet heltall - pr?v igjen!"); number = ""; newLine(); } } } while (i++ < NEWTRIES); // do-while feil("inInt(): Forventet heltall"); return 0; } /** * Les et heltall med spesifiserte tegn som separatortegn. * Det hoppes over eventuelle innledende linjeskift * og separatortegn spesifisert i <CODE>sep</CODE>. Separatortegn angis * som en tekststreng, f.eks. "%&" for ? bruke '%' og '&' som separatortegn. Det gis * feilmelding dersom f?rste * ikke-separator tegn er noe annet enn et siffer. */ public int inInt(String sep) { char c='*'; String number = ""; int i = 0; do { // Les tekst if (!lastItem(sep)) { c = cur.charAt(0); if (c=='-') { number = "-"; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } } else { feil("inInt(String sep): slutt p? filen!"); } // Konverter fra tekst til tall try { return Integer.parseInt(number); } catch (NumberFormatException e) { if (FILE) { feil("inInt(String sep): Forventet heltall i linje " + lineNo + "."); } else { melding("inInt(String sep): Forventet heltall - pr?v igjen!"); number = ""; newLine(); } } } while (i++ < NEWTRIES); // do-while feil("inInt(String sep): Forventet heltall"); return 0; } /** Les et flyttall med blanke som separatortegn. Flyttallet m? ha en * av f?lgende formater: * <pre> * (1) xx.yy (eksempel: 34.22) * (2) .yy (eksempel: .22) * (3) xx (eksempel: 34) * </pre> * Det hoppes over eventuelle innledende blanke tegn (inkludert * tabulatortegn) og linjeskift. * Det gis feilmelding dersom f?rste ikke-blanke tegn er noe annet enn et * siffer. */ public double inDouble() { String number = ""; int i = 0; do { // Les tekst if (!lastItem()) { char c = cur.charAt(0); if (c=='-') { number = "-"; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } if (cur.length() > 1 && (c=='.' & Character.isDigit(cur.charAt(1)))) { cur = cur.substring(1); c = cur.charAt(0); number = number + "."; while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } } } else { feil("inDouble(): slutt p? filen!"); } // Konverter fra tekst til tall try { return Double.valueOf(number).doubleValue(); } catch (NumberFormatException e) { if (FILE) { feil ("inDouble(): Forventet flyttall i linje " + lineNo + "."); } else { melding("inDouble(): Forventet flyttall - pr?v igjen!"); number = ""; newLine(); } } } while (i++ < NEWTRIES); // do-while feil("inDouble(): Forventet flyttall - programmet terminerer"); return 0; } /** Les et flyttall med spesifiserte tegn som separatortegn. * Flyttallet m? ha en * av f?lgende formater: * <pre> * (1) xx.yy (eksempel: 34.22) * (2) .yy (eksempel: .22) * (3) xx (eksempel: 34) * </pre> * Det hoppes over eventuelle innledende linjeskift og separatortegn * spesifisert i <CODE>sep</CODE>. Separatortegn angis * som en tekststreng, f.eks. "%&" for ? bruke '%' og '&' som separatortegn. * Det gis feilmelding dersom f?rste ikke-blanke tegn er noe annet enn et * siffer. */ public double inDouble(String sep) { String number = ""; int i = 0; do { // Les tekst if (!lastItem(sep)) { char c = cur.charAt(0); if (c=='-') { number = "-"; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } if (cur.length() > 1 && (c=='.' & Character.isDigit(cur.charAt(1)))) { cur = cur.substring(1); c = cur.charAt(0); number = number + "."; while (!empty() && Character.isDigit(c)) { number = number + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } } } else { feil("inDouble(String sep): Slutt p? filen!"); } // Konverter fra tekst til tall try { return Double.valueOf(number).doubleValue(); } catch (NumberFormatException e) { if (FILE) { feil("inDouble(String sep): Forventet flyttall i linje " + lineNo + "."); } else { melding("inDouble(String sep): Forventet flyttall - pr?v igjen!"); number = ""; newLine(); } } } while (i++ < NEWTRIES); // do-while feil("inDouble(String sep): Forventet flyttall - programmet terminerer"); return 0; } /** Les en tekststreng med blank som separatortegn. Hopper over * innledende blanke tegn * (inkludert tabulatortegn) og linjeskift, og leser deretter * fram til f?rste blanke * tegn (inkludert tabulatortegn) eller linjeskift (det som kommer f?rst). **/ public String inString() { String s = ""; char c = '*'; if (!lastItem()) { skipWhite(); c = cur.charAt(0); while (!empty() && !Character.isWhitespace(c)) { s = s + c; cur = cur.substring(1); if (!empty()) c = cur.charAt(0); } } else { feil("inString(): Slutt p? filen!"); } return s; } /** Les en tekststreng med spesifiserte tegn som separatortegn. Hopper * over innledende separatortegn * og linjeskift, og leser deretter fram til f?rste separatortegn * eller linjeskift (det som kommer f?rst). Separatortegn angis * som en tekststreng, f.eks. "%&" for ? bruke '%' og '&' som separatortegn. */ public String inString (String sep) { String s = ""; if (!lastItem(sep)) { StringTokenizer st = new StringTokenizer(cur, sep); s = st.nextToken(); int i = cur.indexOf(s); cur = cur.substring(i+s.length(), cur.length()); } else { feil("inString(String sep): Slutt p? filen!"); } return s; } /** Les resten av linjen som en tekststreng (inkludert blanke tegn). */ public String inStringLn() { if (FILE) { String cur0=cur; newLine(); return cur0; } else { if (empty()) newLine(); String cur0=cur; flushLine(); return cur0; } } }