Issue with Reading Multiline Input - java

I'm trying to take user input and modify it a bit, but ran into an issue when the user inputted multiple lines. To fix this I tried:
public static String getInput() {
Scanner sc = new Scanner(System.in);
String input = "";
System.out.println("Awaiting input...");
if(sc.hasNextLine()) {
System.out.println("Combining Input to One Line...");
while(sc.hasNextLine()) {
//System.out.println(sc.hasNextLine());
//System.out.println("check");
input.concat(sc.nextLine() + " ");
//System.out.println(sc.hasNextLine());
//System.out.println("check2");
//System.out.println("check3");
}
}
sc.close();
return input;
}
It seemed to work until it got to the last line of input, where(after debugging a little) it got stuck trying to read sc.hasNextLine(). However, this is very strange, because I put this exact same code in an online compiler, where it works just fine, except for the fact that the input needs to be beforehand. It doesn't wait until there is any input. I'm not very experienced in Java so I could use some help.

If the infinite loop is your problem, than it can be solved by sending a special EOF marker (Ctrl-D on Unix, usually Ctrl-Z on Windows).

Related

Scanner Freezes Program When No Input Is Given

I'm making an application that is mainly used with pipes. At the start of the program, here is how I get all my input:
Scanner scanner = new Scanner(System.in);
List<String> input = new ArrayList<>();
while (scanner.hasNextLine()) {
input.add(scanner.nextLine());
}
scanner.close();
When used with pipes, this works well. For example, running ls | java -jar ... it prints out all the lines given from ls. However, when I just run java -jar ... with no input/pipe, it freezes and nothing happens. Even when I press enter and mash my keyboard it's still stuck. I can only stop the program by using ctrl-c. I think this is because there is nothing to read so Scanner waits until there is something to read. How do I read all lines from System.in without freezing, or is there a better way to do this? Thanks.
Edit:
Whoever marked this as a duplicate clearly did not read my question. My question was to check if the System.in was empty to not freeze the program, not how to get past the input stage. It is freezing because there is nothing in System.in so Scanner is taking forever, but I want to check if there is nothing in System.in.
Answer:
Thank you #QiuZhou for the answer. I modified his second example to get this:
List<String> input = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (reader.ready()) {
String nextLine = reader.readLine();
input.add(nextLine);
}
and it works like a charm.
It's freezing because, as you said, there is nothing to read so Scanner waits until there is something to read, but you want to read all lines from System.in without freezing, it sounds kind of conflicting to me, it's not like reading from a file, we don't know how many lines whoever using your program is going to type in, unless the person tell us. I suggest you define a special character as end of input, for example, done, when the person decides he has finished, just enter done to end waiting:
Scanner scanner = new Scanner(System.in);
List<String> input = new ArrayList<>();
System.out.println("Please enter something. Enter 'done' when finished.");
while (scanner.hasNextLine()) {
String nextLine = scanner.nextLine();
if(nextLine.equals("done"))break;
input.add(nextLine);
}
scanner.close();
To check if there is something to read in System.in without being stuck there, you can do it by using BufferedReader.ready(), as the document reads, Note that in.ready() will return true if and only if the next read on the stream will not block.
System.out.println("Please enter something. Enter 'done' when finished.");
List<String> input = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while(true) {
if (reader.ready()) {
String nextLine = reader.readLine();
if(nextLine.equals("done"))break;
input.add(nextLine);
}
//since ready() will not block, you can add additional logic here, like if it
//takes too long to read next line from input, you can just end here
// break;
}

Code Behaving Differently On Different IDE

I am writing a program that takes information about a track and field competition and then does some computation with it. The issue I'm having now is only in the first user input section.
I first wrote my code in BlueJ and it worked fine. Then, I tried compiling it in JCreator and started getting this error where the program would only receive 3 user inputs before going onto the next piece of code when it should have received 5 (which it did when I compiled in BlueJ).
When I placed a System.out.println statement after the input statement however, the program (in JCreator) DID receive all 5 statements before proceeding. When I commented it out again, it only received 3 statements before continuing. Here is the code below.
String[] events = new String[5];
System.out.println("Please enter the 5 events in this competition.");
for(int i = 0; i < events.length; i++)
{
events[i] = input.nextLine();
System.out.println(i);
}
This is the output with the System.out.println statement.
This is the output with the System.out.println statement commented out.
Change the line
events[i] = input.nextLine();
to
String newLine;
while( (newLine = input.nextLine()).isEmpty() );
events[i] = newLine;
That should consume the extra newline characters and leave you with just the legitimate input in events.
The possible cause of your problem is newline characters, which are interpreted as line. It seems you are having additional newline characters in your input buffer.
You may check your IDE what character is provided when an enter key is pressed.
It seems you are using Scanner class to read input. You may try to wrap your System.in with InputStreamReader, that might help. (not sure, try it out)
Scanner input = new Scanner(new InputStreamReader(System.in));
events[i]=input.nextLine();
Instead you may also try to use BufferedReader to read the input.
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
events[i]=reader.readLine();
Hope it will help!!

Scanner nextLine, stuck in while loop or exiting at odd times

I started doing the CodeAbbey problems last night, they mentioned using stdIn since some the input data is long so copy/paste is much easier than by hand. I had never used the Scanner before so it looked easy enough. I got it working for single line inputs then I got a problem where the input was:
867955 303061
977729 180367
844485 843725
393481 604154
399571 278744
723807 596408
142116 475355
I assumed that nextLine would read each couple, xxxx yyyyy. I put the code in a while loop based on if nextLine is not empty. It runs, but I get weird output, and only after I hit return a few times.
package com.secryption;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("Input: ");
Scanner scanner = new Scanner(System.in);
String input = "";
while(!(scanner.nextLine().isEmpty())) {
input = input + scanner.nextLine();
}
String[] resultSet = input.split("\\s+");
for(String s : resultSet) {
System.out.println(s);
}
}
}
I thought I might need something after adding scanner.nextLine() to input. I tried a space and that didn't help. I tried a newline and that didn't make it better.
This "should" put all the numbers in a single array, nothing special. What am I missing with scanner?
EDIT: Ok so #Luiggi Mendoza is right. I found this How to terminate Scanner when input is complete? post. So basically it it working, I just expected it to do something.
The problem is here:
while(!(scanner.nextLine().isEmpty())) {
input = input + scanner.nextLine();
}
Scanner#nextLine reads the line and will continue reading. You're reading two lines and not storing the result of the first line read, just reading and storing the results of the second.
Just change the code above to:
StringBuilder sb = new StringBuilder();
while(scanner.hasNextLine()) {
sb.append(scanner.nextLine()).append(" ");
}
hasNext() is an end of file indicator that terminates by combining keys control d on Mac ox and control z on windows pressing enter won't send the right message
to JVM

java.util.Scanner: keeps waiting for additional input

Total Java newbie here. Working on one of my very first Java programs. Please help.
Here's what I am trying to achieve:
I need to accept user keyboard input of whitespace separated integers, copy them into an array and process them. KNOWN: user will enter only ONE line of data. I don't know how many numbers, but once they hit Enter, there won't be any more. As user input may contain words and special characters, I need to handle them with neat errors and prompt user to try again. When I run what I wrote below, I get in some kind of infinite loop where Scanner keeps waiting for additional input. How do I tell it it's over and there won't be any more input?
Here's the code:
<!-- language-all: java -->
public static void EnterInts () {
System.out.println("Enter series of integers separated by whitespace. Press Enter key when finished.");
Scanner input = new Scanner(System.in);
while (input.hasNext()){
if (input.hasNextInt(){
int i = input.nextInt();
System.out.println(i);
}
else {
System.out.println("Only integers can be entered. Try again.");
}
}
}
Seems like you should read the single line of input first, then create the Scanner to scan through that single line.
Try using a BufferedReader and InputStreamReader to read the line first:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String str = in.readLine();
And then create the Scanner, perhaps passing a StringBufferInputStream created from the read string into its constructor.

Read Input until control+d

I want to prompt the user to begin entering characters and I want them to be able to enter characters as long as they want until they hit control+d to exit.
For example, they can type a string of numbers like:
1234567
and as soon as they decide to hit control+d the line that they entered will be displayed (so without having to hit return)
I am thinking I'll need a buffered reader or something. Any suggestions?
What rlibby said is spot on: the CTL-D will cause the terminal to flush buffered input to the JVM. However, the keypress event itself is captured and acted on by the terminal and not passed through.
Fortunately, though, it's easy to detect. If the user hits CTL-D on a line of its own, there is no input to flush...which to the JVM is indistinguishable from EOF. Accordingly, System.in.read() will return -1 per the contract of InputStream. If you've wrapped System.in with a BufferedReader, readLine() will return null.
This is my main loop for an interactive command line tool I just wrote:
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
String line;
while((line = systemIn.readLine()) != null) {
// my program loop.
}
One thing worth pointing out is that if the user hits CTL-D after inputting characters (but before hitting return), you'll get those characters. I don't believe there's a way to detect CTL-D when it's not on a line of its own.
DISCLAIMER: I have no idea how this applies to Windows.
http://download.oracle.com/javase/6/docs/api/java/io/BufferedInputStream.html#read%28%29
public class InputTest {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringBuilder out = new StringBuilder();
while (true) {
try {
int c = in.read();
if (c != 4) // ASCII 4 04 EOT (end of transmission) ctrl D, I may be wrong here
out.append (c);
else
break;
} catch (IOException e) {
System.err.println ("Error reading input");
}
}
System.out.println(out.toString());
}
}
You are confusing the roles of your Java program and of the terminal. The terminal buffers input and occasionally supplies it to the Java program, especially after line feeds. Ctrl+D also causes the terminal to make buffered input available, or, if nothing is buffered, to terminate the input. Asking for a program to do something on Ctrl+D is essentially asking it to do something when it reads all available input (and more may become available later). Buffering input on the Java side is going to make things more complicated, rather than less.
Just adding another option for people like me who turn up 9 or so years after the question was asked. If you are using java.util.Scanner, using a String input = in.next(); will drop a NoSuchElementException when Ctrl+d is used. In this case, you can use a try-catch block to catch that particular exception and end execution of your program (either by breaking or changing your iteration value to stop the loop).
import java.util.Scanner;
while (some condition) {
try {
(take your input using the in.next() function here)
...
} catch (java.util.NoSuchElementException e) {
(some condition) = false;
//OR break;
}
}
give this code a try. it actually worked for me
// press ctrl+Z(windows) and ctrl+D(mac, linux) for input termination
StringBuilder out = new StringBuilder();
String text = null;
Scanner scanner = new Scanner( System.in );
while( scanner.hasNextLine() )
{
text = new String( scanner.nextLine() );
out.append( text );
}
scanner.close();
System.out.println( out );
System.out.println( "program terminated" );
In a GUI, you can use a KeyListener.

Categories

Resources