Java - Scanner.nextLine() skipping even when accounting for new line - java

I'm trying to read from a file line by line that is tab delimited. Here's an example of a file:
state 0 start
state 5 accept
transition 0 0 1 x R
transition 1 0 0 x R
I create a Scanner object for the file and set the delimiter to \t. I loop through the file as long as there is a next line. I want to check whether a line begins with state or transition and then get the following information. In the case of lines that begin with state, I use nextInt() and then next() to obtain 0 and start respectively. The issue then arises of going to the next line and repeating the process. I use nextLine() and that's where things get ugly.
I'm aware that nextLine() does not consume the newline character, so I thought to use it twice and it creates more of an issue it seems.
Scanner sc = new Scanner(file);
sc.useDelimiter("\t");
while(sc.hasNextLine())
{
if(sc.next().equals("state") == true)
{
int stateNumber = sc.nextInt();
String state = sc.next();
sc.nextLine();
}
sc.nextLine();
}
That seems to be the relveant code that is creating issues.
Am I misunderstanding how next() works or am i missing something else entirely?

One option here would be to simply read in each entire line in one go, and then split by a delimeter (tab) to get the individual components:
which (sc.hasNextLine()) {
String line = sc.nextLine();
String[] parts = line.split("\\t");
if (parts[0].equals("state")) {
// construct custom object here
}
}
If you want to stick with your original approach then use this:
while(sc.hasNextLine()) {
if (sc.next().equals("state")) {
int stateNumber = sc.nextInt();
String state = sc.next();
}
// consume the entire remaining line, line break included
sc.nextLine();
}
For those lines containing "state" you were making two calls to nextLine(), which would result in an entire line being lost.

Related

Issue with Reading two Int values from a file

I have file with the below data
A,8,43
B,7,42,
C,9,34
I am using the below code to read the data
Scanner input = new Scanner(new File("D:\\test.txt"));
input.useDelimiter(",|\n");
while(input.hasNext()) {
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
When I am executing the program I am getting InputMisMatch exception,
Please suggest what is mistake.
At end of second line you have , and line separator (I am assuming \n) This means you have empty element between these two delimiters.
So in third iteration
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
input.next(); is consuming "", which means input.nextInt() will try to consume C.
To solve this problem you can set delimiter to be combination of one or more commas and line separators like
input.useDelimiter("(,|\n)+");
To improve your code even farther instead of \n you can use \\R added in Java 8 (or \r|\n in earlier versions) to handle all line separators, because currently you don't consider \r as delimiter so it can be treated as valid token.
So better solution would be using
input.useDelimiter("(,|\\R)+"); //for readability
or even
input.useDelimiter("[,\r\n]+");
The problem lies at the use of the useDelimiter method. This method accepts a regular expression as a parameter. You can't just say ,|\n to mean "comma or new line". There are rules.
What you should pass in is "[,\\n]+". This means "one or more characters in the following set: [comma, new line character]".
With the regex that you are passing currently, ,|\n, it means that the delimiter should be either , or \n, but not both. So when it encounters the second line:
B,7,42,
this is what happens:
next reads "B"
nextInt reads "7"
nextInt reads "42"
next reads an empty string that is between the "," and the new line.
nextInt now tries to read the next token "C", which it can't.
EXCEPTION!
I would do things differently -- use one Scanner to parse each line of the File and use a 2nd Scanner nested within the while loop to extract tokens or data from the lines obtained from the first Scanner. For example:
String filePath = "D:\\test.txt";
File file = new File(filePath);
// use try-with-resources
try (Scanner input = new Scanner(file)) {
while (input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScanner = new Scanner(line);
lineScanner.useDelimiter("\\s*,\\s*"); // get comma and any surrounding whitespace if present
String name = "";
int age = 0;
int height = 0;
if (lineScanner.hasNext()) {
name = lineScanner.next();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
height = lineScanner.nextInt();
} // else ... throw exception?
// use name, age, height here
System.out.printf("%s %s %s%n", name, age, height);
lineScanner.close(); // don't waste resources -- return them
}
} catch (IOException e) {
e.printStackTrace();
}

Getting input of one or more rows ending with char sequence not only seperated by space or new line - java

I need to read a user input that begins with "begin", "BEGIN" or "Begin" and the input can be one or more rows until user writes "end", "END" or "End". End is separated from previous String(s) with non-letter character (new line, space or "}" and so on).
I have tried something like this, but I know that's wrong.
String everything = sc.next();
while (true) {
String part = sc.next();
part.toUpperCase();
if (part.equals("END")) {
everything = everything.concat(part);
break;
} else {
everything = everything.concat(part);
}
}
I think your trying to do too many things at once. Your approach could work, but it's making things more complicated. First, get the user input and store it in a list. Once he presses END, then write some code that concatenates it, or whatever you want to do with it.
Scanner sc=new Scanner(System.in);
ArrayList<String> all=new ArrayList<>();
while (true) {
String part = sc.next();
if (part.toUpperCase().equals("END")) {
break;
}
all.add(part);
}
//then do whatever you want with that list.

How to scan a string line, then scan inside that line without creating a nested loop? Java

I want to write a code that scan each line of a file, then it takes each line and scan each next token on it (by a specified delimiter), then compare the token with an input, if there is no match it moves to the next line..etc. But, I couldn't think of any other way that doesn't involves making nested loop! Is there any other way, or a better approach?
try {
Scanner scan = new Scanner(CLOCK_TIME);
while (scan.hasNext()) {
//scan next line
//scan all specified tokens from each line
//if no match repeat, otherwise break
}
}
Use an inner loop, that's what the tool is for (for the life of me, I don't know why you're worried about using it). Just be sure to conserve resources by closing your inner Scanner when you're done with it after the end of the inner loop, and same for your outer Scanner.
Scanner fileScanner = new Scanner(someFile);
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
Scanner innerScanner = new Scanner(line);
while (innerScanner.hasNext()) {
// do whatever
}
innerScanner.close();
}
fileScanner.close();
You could split the line with the split function, but then you'd still have to use a loop to iterate over the resulting array.
To make it easier to look at, you could just pass the line into a function with the inner-nested loop.
i.e.
Scanner fileScanner = new Scanner(someFile);
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
scanLine(line) // call the inner loop function
}
fileScanner.close();
...
private void scanLine(String line) {
Scanner innerScanner = new Scanner(line);
while (innerScanner.hasNext()) {
// inner nested loop code inside separate function
}
innerScanner.close();
}
With what it sounds like you're tying to do, there's no way to process the line without an inner loop.
Unless I'm misunderstanding your question, you want to know if the user input is in a line and skip it if it's not. Why not use String.contains() to find out if the user input is in the line?
try {
Scanner scan = new Scanner(CLOCK_TIME);
while (scan.hasNext()) {
String line = scan.nextLine();
if (line.contains(userInput) {
// Do something
}
}
}

A simple Java code that doesn't work well

The following simple code in Java behaves somewhat in a strange way that I can not understand.
final public class Main
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.print("\nHow many names? ");
int n = sc.nextInt();
String[] a = new String[n];
a[0] = sc.nextLine(); //This line serves no purpose at all. It's useless and should be removed.
for (int i=0; i<n; i++)
{
System.out.print("\nEnter the name:->");
a[i] = sc.nextLine(); //request for input only inside the loop.
}
for (int i=0; i<a.length; i++)
{
System.out.println(a[i]);
}
}
}
The above is working well with no problem at all and displays the number of names inputted into the array a[] on the console but when I remove the line a[0] = sc.nextLine(); //This line serves no purpose at all. It's useless and should be removed., it displays for number of users first. let's say 3. there is no problem but when the loop starts iterating, it will ask for the name and first time the message Enter the name:-> is displayed twice
and the output would be something like shown below.
How many names? 3
Enter the name:-> Don't allow to enter the name here.
Enter the name:->Tiger
Enter the name:->Pitter
Tiger
Pitter
Although I entered 3 for "How many names?", it allows only two names to enter. Why?
Note again that the code shown above is working well. The problem occurs only when the line specified with bold latters in the above paragraph is commented out.
When you use Scanner.nextInt(), it does not consume the new line (or other delimiter) itself so the next token returned will typically be an empty string. Thus, you need to follow it with a Scanner.nextLine(). You can discard the result instead of assigning it to a[0]:
int n = sc.nextInt();
sc.nextLine();
It's for this reason that I suggest always using nextLine (or BufferedReader.readLine()) and doing the parsing after using Integer.parseInt().
You are reading three lines. The problem you have is that nextInt() reads an int value, it doesn't read and consume the end of the line. (A common mistake)
You need the nextLine() after it to say that you want to ignore the rest of the line.
The nextInt call reads from input until the end of the int, but does not read the newline character after the int. So, the first iteration displays "enter the name", then calls nextLine() which reads the end of the line where you typed the number of players (an empty string). Then the second iteration starts and displays "enter the name", and nextLine() blocks until you type a newline character.

How to test for blank line with Java Scanner?

I am expecting input with the scanner until there is nothing (i.e. when user enters a blank line). How do I achieve this?
I tried:
while (scanner.hasNext()) {
// process input
}
But that will get me stuck in the loop
Here's a way:
Scanner keyboard = new Scanner(System.in);
String line = null;
while(!(line = keyboard.nextLine()).isEmpty()) {
String[] values = line.split("\\s+");
System.out.print("entered: " + Arrays.toString(values) + "\n");
}
System.out.print("Bye!");
From http://www.java-made-easy.com/java-scanner-help.html:
Q: What happens if I scan a blank line with Java's Scanner?
A: It depends. If you're using nextLine(), a blank line will be read
in as an empty String. This means that if you were to store the blank
line in a String variable, the variable would hold "". It will NOT
store " " or however many spaces were placed. If you're using next(),
then it will not read blank lines at all. They are completely skipped.
My guess is that nextLine() will still trigger on a blank line, since technically the Scanner will have the empty String "". So, you could check if s.nextLine().equals("")
The problem with the suggestions to use scanner.nextLine() is that it actually returns the next line as a String. That means that any text that is there gets consumed. If you are interested in scanning the contents of that line… well, too bad! You would have to parse the contents of the returned String yourself.
A better way would be to use
while (scanner.findInLine("(?=\\S)") != null) {
// Process the line here…
…
// After processing this line, advance to the next line (unless at EOF)
if (scanner.hasNextLine()) {
scanner.nextLine();
} else {
break;
}
}
Since (?=\S) is a zero-width lookahead assertion, it will never consume any input. If it finds any non-whitespace text in the current line, it will execute the loop body.
You could omit the else break; if you are certain that the loop body will have consumed all non-whitespace text in that line already.
Scanner key = new Scanner(new File("data.txt"));
String data = "";
while(key.hasNextLine()){
String nextLine = key.nextLine();
data += nextLine.equals("") ? "\n" :nextLine;
}
System.out.println(data);
AlexFZ is right, scanner.hasNext() will always be true and loop doesn't end, because there is always string input even though it is empty "".
I had a same problem and i solved it like this:
do{
// process input
}while(line.length()!=0);
I think do-while will fit here better becasue you have to evaluate input after user has entered it.

Categories