Klassen Scanner
Indata till program kan bl a komma från tangentbordet i ett kommandofönster, från textrutor, från filer i datasystemet eller från internet.Dessa data presenteras ofta i form av text dvs strömmar av tecken (bokstäver, siffror, specialtecken, ...). Det är dock vanligt att program inte vill behandla indata tecken för tecken utan i olika grupper t ex ord, heltal, decimaltal, ... Hjälpmedel som sätter ihop tecken till större enheter kallas för "tokenizers" och enheterna kallas för "tokens" (här kommer vi använda de försvenskade varianterna "tok" och "tokar" för enheterna).
Klassen Scanner
är exempel på en tokenizer men Java har flera.
Ett Scanner
-objekt hämtar indata från en ström av tecken, sätter ihop dessa till
ord, heltal, flyttal.
När ett Scanner
-objekt skapas måste man ange varifrån scannern ska hämta tecknen.
Vi börjar med ett enkelt exempel som visar en av de vanligaste användningarna av scannern - läsa in tal från tangentbordet.
Exempel 0: Läs ett heltal och ett flyttal från tangentbordet
Kod | Kommentar |
---|---|
import java.util.Scanner; public class ScannerExample_0 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.print("x: "); double x = scan.nextDouble(); System.out.print("n: "); int n = scan.nextInt(); System.out.println("x^n = " + Math.pow(x, n)); } } | Scannerklassen finns i java.util Skapar ett Scanner-onjekt Skriver en prompter Läser ett decimaltal från tangentbordet Skriver en prompter Läser ett heltal från tangentbordet |
Kopiera ovanstående klass ovan och testkör den!
Satsen
Scanner scan = new Scanner(System.in);
skapar ett Scanner
-objekt som hämtar tecknen från "standard input" som,
i våra fall kommer vara tangentbordet.tangentbordet.
Nedan följer exempel på hur man kopplar scanner-objektet till andra källor än tangentbordet och på många fler metoder
Exempel 1: Lista alla tokar i en sträng
Program | Output |
---|---|
import java.util.Scanner; public class ScannerExample_1 { public static void main(String[] args) { String str = "-2 3.5 x11 5 - 2.000 1,000 1,2 . , 1x"; Scanner scan = new Scanner(str); while (scan.hasNext()) { String token = scan.next(); System.out.println("token: " + token); } } } | token: -2 token: 3.5 token: x11 token: 5 token: - token: 2.000 token: 1,000 token: 1,2 token: . token: , token: 1x |
Scannern delar alltså upp strängen str
i 11 tokar.
Exemplet visar följande Scanner
-relaterade konstruktioner:
Metod | Förklaring |
---|---|
import java.util.Scanner |
Scanner -klassen ligger i paketet java.util |
Scanner(String s) |
Konstruktor som kopplar scanner-objektet till en sträng. |
boolean hasNext() |
Returnerar true om det finns någon mer icke-blankt att hämta, annars false . |
String next() |
Returnerar nästa tok som en sträng. Blanktecken fungerar som avskiljare men ignoreras för övrigt |
Exempel 2: Summera alla heltal i en sträng
Programmet kopplar scannern till samma sträng som i det föregående exemplet. Tokar som kan tolkas som heltal summeras medan övriga skrivs ut.
Program | Output |
---|---|
import java.util.Scanner; public class ScannerExample_2 { public static void main(String[] args) { String str = "-2 3.5 x11 5 - 2.000 1,000 1,2 . , 1x"; Scanner scan = new Scanner(str); int sum = 0; while (scan.hasNext()) { if (scan.hasNextInt()) { sum += scan.nextInt(); } else { System.out.println("Ignored: " + scan.next()); } } System.out.println("Sum of integers: " + sum); } } | Ignored: 3.5 Ignored: x11 Ignored: - Ignored: 2.000 Ignored: 1,000 Ignored: 1,2 Ignored: . Ignored: , Ignored: 1x Sum of integers: 3 |
Vi ser följande nya Scanner
-metoder:
Metod | Förklaring |
---|---|
boolean hasNextInt() |
Returnerar true om det som står på tur att behandlas kan tolkas som ett heltal, annars
false .
|
int nextInt() |
Returnerar nästa token en int . Fel om det inte går att tolka som en int .
|
Exempel 3a: Summera alla flyttal i en sträng (svensk språkinställning)
Samma sträng som i föregående exempel men nu summeras alla tokar som kan tolkas som flyttal.Program | Output |
---|---|
import java.util.Locale; // For language settings import java.util.Scanner; public class ScannerExample_3 { public static void main(String[] args) { Locale.setDefault(new Locale("sv", "SE")); // Swedish String str = "-2 3.5 x11 - 2.000 1,50 1,000 1,2 . , 1x"; Scanner scan = new Scanner(str); double sum = 0; while (scan.hasNext()) { if (scan.hasNextDouble()) { sum += scan.nextDouble(); } else { System.out.println("Ignored: " + scan.next()); } } System.out.println("Sum of doubles: " + sum); System.out.format("Sum of doubles: %3.1f\n", sum); } } | Ignored: 3.5 Ignored: x11 Ignored: - Ignored: 2.000 Ignored: . Ignored: , Ignored: 1x Sum of doubles: 1.7 Sum of doubles: 1,7 |
Locale.setDefault(new Locale("sv", "SE"));
anger att programmet skall
använda svensk standard för tal dvs använda decimalkomma.Observera att konverteringen i första utskriftssatsen inte använder språkinställningen men att
format
-satsen gör det.
Exempel 3b: Summera alla flyttal i en sträng (amerikansk språkinställning)
Samma program som ovan men med inställning för amerikansk standard. Det byder att punkt används för att ange decimaler medan komma som följs av tre siffror används som 1000-talsmarkering.Program | Output |
---|---|
import java.util.Locale; // For language settings import java.util.Scanner; public class ScannerExample_3 { public static void main(String[] args) { Locale.setDefault(Locale.US); // Shorthand for US String str = "-2 3.5 x11 - 2.000 1,50 1,000 1,2 . , 1x"; Scanner scan = new Scanner(str); double sum = 0; while (scan.hasNext()) { if (scan.hasNextDouble()) { sum += scan.nextDouble(); } else { System.out.println("Ignored: " + scan.next()); } } System.out.println("Sum of doubles: " + sum); System.out.format("Sum of doubles: %3.1f\n", sum); } } | Ignored: x11 Ignored: - Ignored: 1,50 Ignored: 1,2 Ignored: . Ignored: , Ignored: 1x Sum of doubles: 1003.5 Sum of doubles: 1003.5 |
Om man inte anger någon Locale
så används datorns språkinställning.
Som detta exempel visar kan resultatet bli helt galet om man inte
har rätt språkinställning!
Anmärkning: Man kan sätta språkinställningarna direkt på Scanner
-objektet
med metoden useLocale(Locale locale)
. Då används inställningarna bara för just detta
Scanner
-objekt.
De två nya Scanner
-metoderna:
Metod | Förklaring |
---|---|
boolean hasNextDouble() | Returnerar true om det som står på tur att behandlas kan tolkas som ett double,
annars false .
Observera att även tal utan decimaler kan tolkas som double .
|
double nextDouble() |
Returnerar nästa tok som en double .
Fel om det inte går att tolka som en double .
|
Det finns många fler metoder för att testa och hämta alla olika datatyper. Se Java-dokumentationen! Observera att scannern inte har någon metod för att läsa enskilda tecken.
Använda scannern på standard input
En vanlig användning av scannern är att koppla den till "standard input" (som i det allra första exemplet) vilket (oftast) är tangentbordet i någon konsol-ruta. Detta görs genom att angeSystem.in
som parameter till konstruktor.
Alla ovanstående exempel fungerar precis på samma sätt.
Exempel 4: Läs tokar från standard input
Programmet läser från standard input. Tokar som kan tolkas som tal räknas och summeras medan tokar som inte kan tolkas som tal bara räknas.Program | In- och output. Input med svart, kursiv stil |
---|---|
import java.util.Scanner; public class ScannerExample_4 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int countNonIntegers = 0; int countIntegers = 0; int sum = 0; while (scan.hasNext()) { if (scan.hasNextInt()) { countIntegers++; sum += scan.nextInt(); // read and sum } else { countNonIntegers++; scan.next(); // read and forget } } System.out.println("Number of integers: " + countIntegers); System.out.println("Sum of integers : " + sum); System.out.println("Number of nonintegers: " + countNonIntegers); } } | $ java ScannerExample_4 1 2 3 + 4 - 100 -100 slut 34 ctrl-D Number of integers: 7 Sum of integers : 44 Number of nonintegers: 3 |
När man använder hasNext()
mot tangentbordet så behövs ett sätt att säga "Nej, nu är det slut på data".
Hur det görs är inte definierat av Java utan beror på vilket datorsystem (eller programmeringsmiljö) man använder.
Tangenten ctrl-D
gäller Unixvärlden vilket visas i exemplet ovan.
Metoderna boolean hasNextLine()
och String nextLine()
är mycket användbara
vid läsning från tangentbordet.
Exempel 5: Räkna rader
Program | In- och output. Input med svart, kursiv stil |
---|---|
import java.util.Scanner; public class ScannerExample_5 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int count = 0; while (scan.hasNextLine()) { count++; scan.nextLine(); // No need to save the line } System.out.println("Number of lines: " + count); } } | $ java ScannerExample_5 1 2 3 4 5 6 7 8 9 10 Number of lines: 5 |
De två nya Scanner
-metoderna:
Metod | Förklaring |
---|---|
boolean hasNextLine() | Om inte hela raden är läst returneras true . Om hela raden är läst men det finns ytterligare en rad returneras också true .I övriga fall returneras false .
|
String nextLine() | Returnerar nästa rad.
Om en rad redan är påbörjad (t ex med next -metoden) returneras resten av raden.
|
Man kan behöva fler Scanner
-objekt. I nedanstående exempel använder vi en scanner på System.in
som läser rader och en annan på de strängar som innehåller de lästa raderna.
Exempel 5a: Räkna både rader och tokar
Program | In- och output. Input med svart, kursiv stil |
---|---|
import java.util.Scanner; public class ScannerExample_5a { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int lineCount = 0; int tokenCount = 0; while (scan.hasNextLine()) { lineCount++; String line = scan.nextLine(); Scanner lineScanner = new Scanner(line); while (lineScanner.hasNext()) { tokenCount++; lineScanner.next(); } } System.out.println("Number of lines : " + lineCount); System.out.println("Number of tokens: " + tokenCount); } } | $ java ScannerExample_5a 1 2 3 4 5 6 7 8 9 10 Number of lines : 5 Number of tokens: 10 |
Använda scannern på filer
Som nämndes initialt kan ettScanner
-objekt kopplas till textfiler.
Här visar vi ett exempel på hur det kan göras men förklarar inte detaljerna i filhanteringen.
Dessa beskrivs i den
minilektion som handlar om att läsa och skriva filer.
Exemplet visar ett program som läser en fil rad för rad och skriver ut de lästa raderna föregånget av ett radnummer. Filen som innehåller programmets java-kod har använts som indata.
Exempel 6: Räkna rader
Program | Output |
---|---|
import java.util.Scanner; import java.io.*; public class ScannerExample_6 { public static void main(String[] args) throws IOException { String filename = "ScannerExample_6.java"; Scanner scan = new Scanner(new FileReader(filename)); int count = 0; while (scan.hasNextLine()) { count++; System.out.println(count + " " + scan.nextLine()); } } } | 1 import java.util.Scanner; 2 import java.io.*; 3 4 public class ScannerExample_6 { 5 public static void main(String[] args) 6 throws IOException { 7 String filename = "ScannerExample_6.java"; 8 Scanner scan = new Scanner(new FileReader(filename)); 9 int count = 0; 10 while (scan.hasNextLine()) { 11 count++; 12 System.out.println(count + " " + scan.nextLine()); 13 } 14 } 15 } |