ubuntuusers.de

Java will den String nicht einlesen

Status: Gelöst | Ubuntu-Version: Ubuntu 12.04 (Precise Pangolin)
Antworten |

313373n3wb33

(Themenstarter)
Avatar von 313373n3wb33

Anmeldungsdatum:
7. November 2012

Beiträge: 71

Vergesst es mir ist die Lust vergangen. Danke dass ihr mir versucht hab den richtigen Weg zu zeigen, aber ohne Lösung bringt mir das ganze hier gar nichts.

Ich mach einfach etwas anderes. Es ist ja nicht so als müsste ich diesen Physikrechner fertig Programmieren der war eigentlich nur als Übung da die mir jetz mehr oder weniger nichts gebracht hat.

Sry an Google Benutzer.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

@313373n3wb33: Eingaben (etwa aus CSV-Files) können z.B. auch so aussehen:

1
zahl,zahl,zahl

Dann würde bei jedem nextInt() die jeweils nächste Zahl ausgeliefert werden. Das macht auch durchaus Sinn, da der Scanner eben nicht auf Eingaben vom Terminal spezialisiert ist, sondern allgemein für das Lesen aus Datenströmen angewendet werden kann. Stell dir hier einfach einen Cursor vor, der nach jedem Lesen an die Stelle direkt hinter dem zuletzt ausgelieferten Datensatz (hier: die jeweilige Zahl) rutscht.

Eine Zahleneingabe durch den Nutzer über System.in besteht nun aus folgenden Bestandteilen:

1
Zahl | Newline

Nach dem Aufruf von nextInt() rutscht der Cursor also an die Stelle zwischen Zahl und Newline.

Jetzt wird es nötig, nextLine() aufzurufen. Diese Methode hat die Aufgabe, all das, was zwischen der aktuellen Cursorposition und dem nächsten Newline-Zeichen steht, auszugeben (in deinem Fall: leerer String). Nach Aufruf dieser Methode steht die Cursorposition am Anfang der nächsten Zeile.

Aus diesem Grund musst du den für dich als unnötig empfundenen zusätzlichen Aufruf von nextLine() dazwischen quetschen, damit der dann folgende nextLine()-Aufruf den von dir erwarteten Text ausliefern kann. Vielleicht ist es ja jetzt klarer geworden, was meine Vorposter von dir wollen... 😉

Im Übrigen ist es bei Nutzereingaben, oftmals einfacher, anstatt nextInt() lieber ein Integer.valueOf(scanner.nextLine()) anzuwenden. Das tut eher das, was man eigentlich haben möchte (durch den Nutzer eingetippte *Zeile* als Integer interpretieren) und ist dementsprechend auch weniger fehleranfällig.

xabbuh Team-Icon

Anmeldungsdatum:
25. Mai 2006

Beiträge: 6411

313373n3wb33 schrieb:

Vergesst es mir ist die Lust vergangen. Danke dass ihr mir versucht hab den richtigen Weg zu zeigen, aber ohne Lösung bringt mir das ganze hier gar nichts.

Du hattest die Lösung doch?! Das einzige, was Du bei Dir verändern kannst, ist, auf die Zuweisung des Rückgabewertes zur Variablen blind zu verzichten.

313373n3wb33

(Themenstarter)
Avatar von 313373n3wb33

Anmeldungsdatum:
7. November 2012

Beiträge: 71

Eingabestreams:

String-→ Streckeneinheit: M *Unsichtbarer-Nächste-Zeile-beginn-code-der-automatisch-nach-string-eingabe-hierher-geschrieben-wird*

Int-→ Streckenwert: 8 *Kein-Nächste-Zeile-beginn-code-der-automatisch-hierher-geschrieben-wird-da-es-um-die-Zahlen-und-nicht-um-die-Int-geht*

String-→ Zeiteinheit: *Versteckter-Nächste-Zeile-Beginn-Code-da-!Letzter-Eingabestream-noch-in-dieser-Zeile-ist!-und-weil-scan-diese-line-wird-scann-abgebrochen*

Int-→ Zeitwert: 2 *wieder-kein-versteckter-code*

Auf gut Deutsch man kann nach einem Int einen String nicht direkt einlesen, sondern muss den Eingabestream von Int zuerst beenden. In meinem Fall wurde er also durch den 2ten String beendet.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Nee, nicht ganz. Es ist nicht so, dass der Scanner zwischendurch in einer Art "Zahlenmodus" ist, wo man ihn erst wieder rausholen müsste. Vielmehr ist der Cursor des Scanners einfach noch nicht am Anfang der nächsten Zeile, sondern eben erst hinter der zuletzt ausgegebenen Zahl. Man muss ihn erst dazu bringen, sozusagen die aktuelle Zeile zu beenden und in die nächste zu springen. Das kann man am Besten mit einem zusätzlichen nextLine() machen. Die Newline-Zeichen hat man nach jeder Eingabe bzw jedem Enter-Drücken mit drin. Nur werden die bei den Ausgaben weg gelassen, sodass man sie als Benutzer der Scanner-API halt nicht direkt sieht.

Hier übrigens ein sehr einfach gehaltenes Beispiel, welches den schon von mir vorgeschlagenen Weg über eine grundsätzliche Abfrage von nextLine() geht:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.Scanner;

public class Benutzereingabe {
    private static final Scanner eingabeleser = new Scanner(System.in);
    
    public static String erfrageText() {
        return eingabeleser.nextLine();
    }
    
    public static int erfrageZahl() {
        return Integer.parseInt(eingabeleser.nextLine());
    }
    
    public static void main(String[] args) {
        System.out.println("Bitte eine Zahl eingeben:");
        int zahl = erfrageZahl();
        System.out.println("Jetzt bitte beliebigen Text eingeben:");
        String text = erfrageText();
        System.out.println("Zahl war: " + zahl);
        System.out.println("Text war: " + text);
    }
}

Ich finde das deutlich robuster, da hierdurch garantiert wird, dass der Cursor *immer* am Anfang der nächsten Zeile steht, nachdem etwas eingelesen wurde.

Die Reaktion auf Fehleingaben durch den Benutzer (z.B. keine Zahl, obwohl eine erwartet wird) habe ich hier erstmal weg gelassen.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

rklm hatte es hier schon mal geschrieben, ich erläutere es nochmal etwas ausführlicher:

Zu Anfang stehen im Datenpuffer der Tastatur die Zeichen:
| 1 | 2 | 3 | \n | t | e | x | t | \n |
 =^===^===^=
Du liest diesen Integer aus. 
Danach steht dort immer noch:    (denn Du hattest nach der Zahl doch ein [Enter] eingegeben, nicht wahr ?)
| \n | t | e | x | t | \n |
 ==^=
Das ist das, was Du mit Deinem 1.Zeilenlesen aus dem Puffer holst ! (also kein Text, nur das [Enter])
Danach geht es normal weiter mit:
| t | e | x | t | \n |
 =^===^===^===^====^=
Das wird beim 2.Zeilenlesen abgeholt: der "text" und das [Enter].

Merke: das [Enter] wird immer nur beim Zeilenlesen abgeholt, aber nicht beim Integerlesen !

Siehst Du es jetzt ?

LG,

track

313373n3wb33

(Themenstarter)
Avatar von 313373n3wb33

Anmeldungsdatum:
7. November 2012

Beiträge: 71

Also bei nextInt wird /n (nächster Absatz) nicht angewendet. Später wird aber ein, durch nextInt zurückgelassenes, /n vom nächsten nextLine benutzt. Dadurch wird die Eingabe geöffnet und gleich danach durch /n die Zeile beendet. Durch ein dazwischen eingegebenes nextLine(); wird die Zeile beendet.

Hab ich das so richtig?

Die hätten mir das gleich sagen sollen.xD

Mein Problem war das ich den Eingabestream nicht kannte. Und dass eine Eingabe hier nicht durch den /n nicht automatisch beendet wird. Danke an alle Beteiligten, Ich wünschte ich könnte euch nen Cafe für die Umstände und meine schlechte Laune zahlen. :/

MfG N3w

Hefeweiz3n Team-Icon

Moderator, Webteam
Avatar von Hefeweiz3n

Anmeldungsdatum:
15. Juli 2006

Beiträge: 5814

Wohnort: Ankh-Morpork

313373n3wb33 schrieb:

Also bei nextInt wird /n (nächster Absatz) nicht angewendet. Später wird aber ein, durch nextInt zurückgelassenes, /n vom nächsten nextLine benutzt. Dadurch wird die Eingabe geöffnet und gleich danach durch /n die Zeile beendet. Durch ein dazwischen eingegebenes nextLine(); wird die Zeile beendet.

Hab ich das so richtig?

Bis auf die Terminologie, ja 😉. Benutzen und öffnen sind hier eher die falschen Begriffe. Der Eingabescanner bleibt ja die ganze Zeit über offen. Wichtig ist hier das Daten ab dem Cursor (Zeiger) gelesen (Was du wohl mit "Benutzen" meinst) werden. Und zwar je nach Methode unterschiedlich viele. nextInt() beendet das auslesen nach dem letzten Zeichen was eine Zahl ist, nextLine() halt nach dem Zeilenumbruch. Da \n = newline keine Zahl ist wird es von nextInt() halt nicht gelesen, weshalb der Cursor davor stehenbleibt.

Das Verhalten ist, so betrachtet, sehr logisch und konsistent, wie du sagst muss man dafür aber natürlich wissen wie genau das funktioniert. Ich hoffe das ist jetzt bei dir der Fall 😉.

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Ich glaube, das was hinter den Kulissen vor sich geht, ist immer noch die große Unbekannte für unseren Threadersteller. Da spielt noch viel Phantasie mit rein. Vielleicht fragt er sich ja gerade: "Hackt sich Java da etwa in mein Terminal ein und bewegt einfach so den Cursor...?" 😉

Aber egal: Das grundsätzliche Prinzip wurde jetzt anscheinend verstanden und der Rest kommt schon irgendwann im Laufe der Zeit. ☺

313373n3wb33

(Themenstarter)
Avatar von 313373n3wb33

Anmeldungsdatum:
7. November 2012

Beiträge: 71

Das ganze funktioniert über Tokens nicht wahr?

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13177

313373n3wb33 schrieb:

Das ganze funktioniert über Tokens nicht wahr?

Token sind die Ausgabe des Scanners - kein Zwischenprodukt. Ein Scanner zerlegt einen uniformen Eingabestrom von Zeichen in einen Strom von Tokens. Das sind jeweils Gruppen von aufeinander folgenden Zeichen, z.B. alle Ziffern, die eine Ganzzahl bilden.

Hefeweiz3n Team-Icon

Moderator, Webteam
Avatar von Hefeweiz3n

Anmeldungsdatum:
15. Juli 2006

Beiträge: 5814

Wohnort: Ankh-Morpork

rklm hat das mit den Tokens ja schon erklärt. Das mit dem Cursor ist aber noch eine Ebene tiefer, vor den Token. Weil du kannst ja auch einfach einen einzelnen Bustaben auslesen anstatt eines kompletten Tokens. Den Cursor kannst du dir einfach wie deinen Finger vorstellen, mit dem du beim Lesen in einem Text mitgehst um nicht zu vergessen wo du bereits warst.

Aktuelle Position ----------+
                            |
Text Foo Bar, eine Zahl: 123\n
Und hier beginnt die neue Zeile

Das kann man dann sowohl so implementieren das man auch auf bereits gelesene Bustaben erneut zurückgreifen kann oder auch nicht.


Achtung: Wenn du das folgende nicht verstehst lass es einfach, oder aber wenn du mal Zeit und Muße hast arbeite dich in die Grundlegenden Informatikmodelle wie Listen und Bäume ein und versuche es dann noch einmal 😉.

Man könnte das ganze z.B. mit einer einfach verketteten Liste lösen, dann hätte jeder Buchstabe eine Referenz (Verweis) auf den nächsten besitzt. Bei einer doppelt Verketteten Liste hätte man dann auch eine Referenz auf den jeweiligen vorherigen Buchstaben.

Einfach verkettet
+---+   +---+   +---+   +---+
| T |==>| e |==>| x |==>| t |
+---+   +---+   +---+   +---+
Doppelt verkettet
+---+   +---+   +---+   +---+
| T |<=>| e |<=>| x |<=>| t |
+---+   +---+   +---+   +---+

Näher an der Hardware dran (z.B. mit C/C++), und damit auch effizienter und schneller, setzt man sowas mit Pointern um, Pointer sind dabei Variablen die direkt auf einen Speicherbereich verweisen in dem dann der nächste Buchstabe zu finden ist.

313373n3wb33

(Themenstarter)
Avatar von 313373n3wb33

Anmeldungsdatum:
7. November 2012

Beiträge: 71

@Rklm: Ja ich sag int bla input.nextInt und es wird ein Token erstell der bis zur nächsten nicht-Zahl (Sprich Ende der Zahlenfolge) hält. Sobald der abgelaufen ist wird die variable bla in nem Variablenspeicher o.ä. gesichert und verweist auf einen Speicher bereich in dem sich meine Eingegebene Zahl befindet.

@Hefe:

Ich merk schon dass ich hier das gesamte Thema warscheinlich falsch verstanden habe. Kann mich da sonst jemand an nen Guten Artikel o.ä. verlinken? Dann könnte ich ein bischen Geistreicher hier rein Posten. x)

MfG N3w

Hefeweiz3n Team-Icon

Moderator, Webteam
Avatar von Hefeweiz3n

Anmeldungsdatum:
15. Juli 2006

Beiträge: 5814

Wohnort: Ankh-Morpork

313373n3wb33 schrieb:

@Rklm: Ja ich sag int bla input.nextInt und es wird ein Token erstell der bis zur nächsten nicht-Zahl (Sprich Ende der Zahlenfolge) hält. Sobald der abgelaufen ist wird die variable bla in nem Variablenspeicher o.ä. gesichert und verweist auf einen Speicher bereich in dem sich meine Eingegebene Zahl befindet.

Du vermischst da verschiedene Arten von Tokens 😉.

@Hefe:

Ich merk schon dass ich hier das gesamte Thema warscheinlich falsch verstanden habe. Kann mich da sonst jemand an nen Guten Artikel o.ä. verlinken? Dann könnte ich ein bischen Geistreicher hier rein Posten. x)

Die Java Insel ist eine sehr gute Quelle 😉.

Covex

Anmeldungsdatum:
11. November 2013

Beiträge: Zähle...

Hi für den fall du einfach nur den code möchtest habe ich mir mal 10min zeit genommen und so ein programm geschreiben.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.util.InputMismatchException;
import java.util.Scanner;

public class UniformMotionCalculator {

	private float var_one;
	private float var_two;

	private Scanner input;

	public static void displayHelp() {
		System.out.println("No arguments - View help\n");
		System.out
				.println("  -v   Calculates the velocity from the time and distance");
		System.out
				.println("  -d   Calculates the distance from the velocity and time");
		System.out
				.println("  -t   Calculates the time from the velocity and distance");
		System.exit(0);
	}

	public UniformMotionCalculator(String arg) {
		input = new Scanner(System.in);

		if (arg.startsWith("-v")) {
			getData("Distance in km: ", "Time in h: ");
			System.out.println("Velocity: " + var_one / var_two + " km/h");
		} else if (arg.startsWith("-d")) {
			getData("Velocity  in km/h: ", "Time in h: ");
			System.out.println("Distance: " + var_one * var_two + " km");
		} else if (arg.startsWith("-t")) {
			getData("Distance in km: ", "Velocity  in km/h: ");
			System.out.println("Time: " + var_one / var_two + " h");
		} else {
			displayHelp();
		}
	}

	public void getData(String name_one, String name_two) {
		try {
			System.out.print(name_one);
			var_one = input.nextFloat();
			System.out.print(name_two);
			var_two = input.nextFloat();
		} catch (InputMismatchException e) {
			System.out.println("No valid input!");
			System.exit(0);
		}
	}

	public static void main(String[] args) {
		if (args.length == 1 && args[0].length() == 2) {
			new UniformMotionCalculator(args[0]);
		} else {
			UniformMotionCalculator.displayHelp();
		}
	}

}