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
Related
I have a command-line game and am testing with JUnit, this is the test:
#Test
public void testBattle() throws IOException{
String input = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n";
provideInput(input);
actual = new File("src/main/testFiles/testBattle.txt");
expected = new File("src/main/testFiles/testBattleExpected.txt");
PrintStream o = new PrintStream(actual);
System.setOut(o);
ui.gameLoop();
assertTrue(FileUtils.contentEqualsIgnoreEOL(actual, expected, null));
}
And this is the provide input method:
private void provideInput(String data) {
String newdata = data.trim();
testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
}
I'm doing scanner nextline so:
command = input.nextLine().toLowerCase().trim();
where "input" here represents the scanner object
but I'm still getting this error, specifically when the first "normal attack" is passed into System.in
java.util.NoSuchElementException: No line found
on that line above. I thought nextline ignored whitespace? If not did I format my string wrong to not include it?
EDIT:
From the first few lines of UI.gameLoop() I only initialize the scanner once.
public void gameLoop() throws IOException, JsonSyntaxException {
input = new Scanner(System.in);
engine = new GameEngine(path);
I thought nextline ignored whitespace?
Nope. According to the javadocs, it reads past the next end-of-line sequence (or to EOF), and then returns everything up to but not including the end-of-line sequence.
If you are getting
java.util.NoSuchElementException: No line found
that means that the Scanner has already reached the end of the input stream, or (maybe) the Scanner is trying to read from an input stream that was prematurely closed somewhere else in your code.
We can make guesses about what the real problem is, but without seeing >>your<< minimal reproducible example, we can't take this much further.
Actually, I just spotted a clue:
... I am testing with JUnit ...
This is possibly at the root of your problems. A JVM can only "read to the end of System.in" once in its lifetime. If you have two or more JUnit tests that need to do this, it is going to be difficult, unless you can find a way to "mock" the System.in variable.
It may be simpler to reorganize your code so that you take the input from some stream that is passed to your game code as a parameter. By reorganizing you can make it easier to write unit tests.
There's not a lot to go on, but I'm guessing you're creating multiple Scanners, one for each time you want to read a line. This usually works ok interactively since humans are slow typers, but fails when each Scanner's readahead ends up consuming multiple lines.
You can see the difference in this MCVE:
import java.util.*;
import java.io.*;
class Foo {
public static void main(String[] args) throws Exception {
String newdata = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n".trim();
ByteArrayInputStream testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
boolean includeBug = Boolean.valueOf(args[0]);
if (includeBug) {
for(int i=0; i<8; i++) {
Scanner input = new Scanner(System.in);
System.out.println("Read: " + input.nextLine());
}
} else {
Scanner input = new Scanner(System.in);
for(int i=0; i<8; i++) {
System.out.println("Read: " + input.nextLine());
}
}
}
}
When includeBug is true, it creates a new Scanner for each line and crashes like you say. If it's false, it creates a single Scanner and works correctly:
$ javac Foo.java
$ java Foo true
Read: go forward
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at Foo.main(Foo.java:17)
$ java Foo false
Read: go forward
Read: go left
Read: take Pointy Stick
Read: go backward
(etc)
Are you checking if it has a next line? With Scanners, you usually either have to handle the exception (not really something I'd prefer) or you have to use the hasNextLine() method to avoid the exception.
while (input.hasNextLine()) {
command = input.nextLine().toLowerCase().trim();
}
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).
This might be very very basic or may be something I am totally missing. I have started doing some competitive programming on online channels. I have to read comma separated strings and do some manipulations around it but the problem is that I do not know the number of lines of input. Below is the input example
Input 1
John,Jacob
Lesley,Lewis
Remo,Tina
Brute,Force
Input 2
Hello,World
Java,Coder
........
........
//more input lines
Alex,Raley
Michael,Ryan
I am trying to read input and breaking when end of the line is encountered but with no luck. This is what I have been trying
//1st method
Scanner in = new Scanner(System.in);
do{
String relation = in.nextLine();
//do some manipulation
System.out.println(relation);
}while(in.nextLine().equals("")); //reads only first line and breaks
//2nd method
Scanner in = new Scanner(System.in);
while(in.hasNext()){
String relation = in.next();
System.out.println(relation);
if(relation.equals("")){
break;
}
}
//3rd method
Scanner in = new Scanner(System.in);
while(true){ //infinite loop
String relation = in.nextLine();
System.out.println(relation);
if(relation.equals("")){
break;
}
}
Can somebody help here.
PS: Please don't judge. I am new to competitive programming though I know how to take user input in java and difference between next() and nextLine().
Im not gonna write why you shouldn't use Scanner. There are numerous articles why you shouldn't use Scanner in competitive programming. Instead use BufferedReader.
In competitive programming they redirect the input to your code from file.
It works like ./a.out > output.txt < input.txt for example.
So read until null is detected in the while loop.
public static void main(String args[] ) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null)
{
//System.out.println(s);
}
}
For testing through your keyboard, to simulate a null from your keyboard:
Press Ctrl+D. It will break out of the while loop above.
It should be fairly easy. Try
while(in.hasNextLine()){
String relation = in.nextLine();
if("exit".equalsIgnoreCase(relation))break;
//do some manipulation
System.out.println(relation);
}
The method Scanner#hasNextLine simply checks if there is a next line in the input, doesn't really advance the scanner. On the other hand, Scanner#nextLine reads the input as well as advances the scanner.
Update you might want to put some condition to exit the loop. E.g. the above snippet stops reading more input after it encounters a string "exit".
All your methods can be improved.
But let's consider your second method of while loop.
Scanner in = new Scanner(System.in);
String s;
while(in.hasNext()){
s=in.nextLine();
System.out.println(s);
}
In the same way, you can change each of your codes.
Also you can use BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); to buffer your input then check for in.readLine()) != null
Other than the above two methods (Buffered Reader method & Scanner method), I have another method for solving this issue. Have a look at the following code, you can catch NoSuchElementException to solve this issue , though I didn't recommended this as Exception handling is a costly process .
Out of all the methods, the Buffered should only be used during Competitive Coding as it has the least Complexity.
import java.util.*;
public class Program
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
while(true)
String a=sc.next();
System.out.print(a);
}
catch(NoSuchElementException k)
{
}
}
}
I'm convinced this is a product of how the string.replaceAll() method works, but for some odd reason its making my loop run twice when you type anything with a space in it?
public class TestCode{
public static void main(String[] args) throws IOException{
Scanner scan = new Scanner(System.in);
String input = "";
while(!input.equals("X")){
System.out.println("Prompt user for input");
input = scan.next().toUpperCase();
calculatePolynomial(input);
}
}
public static void calculatePolynomial(String input){
//Clean up entry removing spaces and extracting polynomial names
String calculation = input.replaceAll("\\s", "");
System.out.println(calculation);
}
}
The idea was to have the code run... printing out the message, prompting input. Then process the input and do some stuff. Repeat the process over and over until the sentinel value 'x' is entered.
But when you type input that contains a space it, for some reason, runs the loop as if each word was now separate input. So if you enter three words, it just runs the loop three times instead of once.
I just want the user's input to be without spaces and without a nightmare of logical errors.
When using a Scanner, by default, next() tokenizes the input by whitespace. So if the user enters two words separated by whitespace, your loop will run twice.
To get the entire input in the user's input line, try using the nextLine() method instead.
I'm doing a simple program regarding methods.
But I have one problem. Everything is already working except when looping.
When I choose to loop again. The program skips on inputting the name. And proceeds directly to the year and section.
Here's the code:
public static void main(String[] args) {
do{
System.out.println("Input info:");
name=stringGetter("Name: ");
yearandsec=stringGetter("Year and section: ");
sex_code=charGetter("Sex code: " + "\n" + "[M]" + "\n" + "[F]:");
scode=intGetter("Scholarship code: ");
ccode=intGetter("Course code: ");
units=intGetter("Units: ");
fee_per_unit=doubleGetter("Fee per unit: ");
misc=doubleGetter("Miscellaneous: ");
display();
switches(scode, units, fee_per_unit, misc);
System.out.println("Another?");
dec=rew.nextInt();
}while(dec==1);
}
Here's the method getting the value for name together with the year and section:
public static String stringGetter(String ny){
String sget;
System.out.println(ny);
sget=rew.nextLine();
return sget;
}
I'm really annoyed with this problem, and I don't have any idea on how to fix this. Please help. thanks
Here is a simpler and more complete program that reproduces the error:
public static Scanner rew = new Scanner(System.in);
public static void main(String[] args) {
int dec;
do {
System.out.println("Input info:");
String name=stringGetter("Name: ");
String yearandsec=stringGetter("Year and section: ");
dec=rew.nextInt();
} while(dec==1);
}
public static String stringGetter(String ny){
System.out.println(ny);
return rew.nextLine();
}
The problem is that after calling nextInt() the call to nextLine() reads up to the new line after the int (giving a blank line), not up to the next new line.
If you change dec to a String and change dec=rew.nextInt(); to dec=rew.nextLine(); then it will work fine. Here is a complete example that you can copy and paste into a blank file to see that it works correctly:
import java.util.*;
public class Program
{
public static Scanner rew = new Scanner(System.in);
public static void main(String[] args) {
String dec;
do {
System.out.println("Input info:");
String name = stringGetter("Name: ");
String yearandsec = stringGetter("Year and section: ");
dec = stringGetter("Enter 1 to continue: ");
} while(dec.equals("1"));
}
public static String stringGetter(String ny){
System.out.println(ny);
return rew.nextLine();
}
}
You may also want to consider adding proper parsing and validation to your program. Currently your program will behave in an undesirable way if the user enters invalid data.
The line:
dec = rew.nextInt();
Is reading an int value from the input stream and is not processing the newline character, then when you come back to point where you get the name at which point a new line is still in the Reader's buffer and gets consumed by the stringGetter returning an empty value for name.
Change the line to do something like:
do {
//....
s = stringGetter("Another (y/n)? ");
} while ("y".equals(s));
Well you haven't told us what "rew" is, nor what rew.nextInt() does. Is it possible that rew.nextInt() is waiting for the user to hit return, but only actually consuming one character of the input - so that the next call to rew.nextLine() (for the name) just immediately takes the rest of that line? I suspect that's what's happening because you're using System.in - usually reading from System.in only gives any input when you hit return.
(It's possible that this is also only a problem on Windows - I wonder whether it consumes the "\r" from System.in as the delimiter, leaving "\n" still in the buffer. Not sure.)
To test this, try typing in "1 Jon" when you're being asked whether or not to continue - I think it will then use "Jon" as the next name.
Essentially, I think using Scanner.nextInt() is going to have issues when the next call is to Scanner.nextString(). You might be better off using a BufferedReader and calling readLine() repeatedly, then parsing the data yourself.