When parsing text file input does not move to next line - java

I am looking for a little help. I have done quite a bit of googling with little success.
I am new to programming and am sure this is a silly oversight on my part.
The below code is intended to read through a .txt document that is tab delimited. The .txt file is formatted into six columns. Currently, as I move through the file I parse the string to the appropriate value type and assign it to its respective variable. Code is here:
try {
s = new Scanner(new BufferedReader(new FileReader(file))).useDelimiter("\t");
while (s.hasNextLine()) {
group = Integer.parseInt(s.next());
death = Integer.parseInt(s.next());
name = s.next();
sex = s.next();
age = Integer.parseInt(s.next());
fare = Double.parseDouble(s.next());
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
} finally {
if (s != null) {
s.close();
}
}
When I reach the last column of the first row, the variable fare is set to row 1 column 6 AND row 2 column 1. For some reason the line break is not triggering the while loop to restart.
Can anyone help me understand why the while loop does not restart at the end of the line?
File looks like this:
1 5 Bryan male 25 211.3375
1 2 Jimmy male 22 151.5500
There is about 1200 lines of this. When running this loop I get the below error when attempting to set fare = 211.3375 at the end of the first row. For some reason, the line break isn't resetting the loop. I can only assume that the line break is not interpreted as a tab but do not know how to correct this.
Exception in thread "main" java.lang.NumberFormatException: For input string: "211.3375
1"

You're checking Scanner#hasNextLine() but then reading multiple Scanner#next(), a dangerous thing to do. I suggest if you check for next line, you should read next line, and then parse through that line.
e.g.,
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
group = lineScanner.nextInt();
death = lineScanner.nextInt();
name = lineScanner.next();
sex = lineScanner.next();
age = lineScanner.nextInt();
fare = lineScanner.nextDouble();
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
But even this is somewhat dangerous because I'm calling Scanner#next...() without first checking. And so perhaps safer would be to do
String[] tokens = line.split("\\s+");
Then count the tokens length to be sure that it's right, and then parse each individual token that needs parsing to numeric type.
Or you could do something like:
while (s.hasNextLine()) {
String line = s.nextLine();
Scanner lineScanner = new Scanner(line);
if (lineScanner.hasNextInt()) {
group = lineScanner.nextInt();
}
if (lineScanner.hasNextInt()) {
death = lineScanner.nextInt();
}
if (lineScanner.hasNext()) {
name = lineScanner.next();
}
if (lineScanner.hasNext()) {
sex = lineScanner.next();
}
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
}
if (lineScanner.hasNextDouble()) {
fare = lineScanner.nextDouble();
}
lineScanner.close();
System.out.println("Class = " + group); // Test that value is being assigned
System.out.println("Death = " + death); // Test that value is being assigned
System.out.println("Name = " + name); // Test that value is being assigned
System.out.println("Gender = " + sex); // Test that value is being assigned
System.out.println("Age = " + age); // Test that value is being assigned
System.out.println("Fare = " + fare); // Test that value is being assigned
}
or use try/catch blocks to check for bad files.

Related

Basic file scanner exception/issue

I'm working on a program for my class that asks for me to read data from a txt file, then display it back. I have created a while loop that reads for hasNext, but I'm running into an exception. It says it's a "no such element exception" and I have no idea why. The loop works for 5 iterations, then gives me the exception
import java.util.Scanner;
import java.text.DecimalFormat;
import java.io.*;
public class Project2_William_Walker
{
public static void main (String[]args) throws IOException
{
File file = new File ("boarding.txt");
Scanner inputFile = new Scanner(file);
DecimalFormat df = new DecimalFormat("0.00");
String title = "Madison Kennel & Grooming";
String fName;
String lName;
String breed;
String weight;
String age;
double highRisk = 20.00;
while (inputFile.hasNext())
{
fName = inputFile.nextLine();
lName = inputFile.nextLine();
breed = inputFile.nextLine();
weight = inputFile.nextLine();
age = inputFile.nextLine();
inputFile.nextLine();
System.out.println(fName + " " + lName + " " + breed + " " + weight + " " + age);
System.out.println();
}
inputFile.close();
System.out.println("End of Program");
}
}
So in my txt file I have a list that has a first name, then a last name, followed by the breed, the weight and then the age. Looks like this:
Will
Walker
Pug
3
4
John
Appleseed
Retriever
15
7
..and so forth for 4 more entries. My loop gets through the first 5 just fine, but then poops out on the 6th and final time through. Thanks for any help!
You are reading 6 lines in the loop, but the loop condition only checks if there is (at least) 1 line to read.
You probably have an extra blank line at the end of the input file, which causes hasNext() to return true after reading in the last block of data.
You would be better to use a for loop the iterates 5 times, each time checking if there's a line available, and each time saving the data into an array.
Something like:
String[] data = new String[5];
while (inputFile.hasNext()) {
Arrays.fill(data, null); // clear out array, in case input is short
for (int i = 0; i < 5 && inputFile.hasNext(); i++)
data[i] = inputFile.nextLine();
if (inputFile.hasNext())
inputFile.nextLine();
System.out.println(data[0] + " " + data[1] + " " + data[2] + " " + data[3] + " " + data[4]);
System.out.println();
}
inputFile.close();
Let's find the source of your problem. To easily do that, let's "map" your nextLine() calls to the file content:
Iteration Code Read line from file
1 fName = inputFile.nextLine(); Will
1 lName = inputFile.nextLine(); Walker
1 breed = inputFile.nextLine(); Pug
1 weight = inputFile.nextLine(); 3
1 age = inputFile.nextLine(); 4
1 inputFile.nextLine(); (empty line between blocks)
2 fName = inputFile.nextLine(); John
2 lName = inputFile.nextLine(); Appleseed
2 breed = inputFile.nextLine(); Retriever
2 weight = inputFile.nextLine(); 15
2 age = inputFile.nextLine(); 7
2 inputFile.nextLine();
As you can see, the last statement inputFile.nextLine() tries to read a line from a file, but there is nothing more to read anymore, because "7" was the last line. So your problem is that you expect that there is always an empty line after a block.
A quick fix would be adding a check, like this:
if (inputFile.hasNextLine())
inputFile.nextLine();
But this can cause trouble if there is no empty line to split two blocks and the next block starts right after the last one.
To avoid such problems in the first place, I would recommond a different file structure. You can for example use a csv with a "," as the delimiter:
Will,Walker,Pug,3,4
John,Appleseed,Retriever,15,7
And read it like this:
final String line = inputFile.nextLine(); // read a single line
final String[] items = line.split(","); // split that line using ','
fName = items[0];
lName = items[1];
breed = items[2];
weight = items[3];
age = items[4];
System.out.println(fName + " " + lName + " " + breed + " " + weight + " " + age);
And to make it even better: create a model class which holds the necessary fields to represent such a line (or a block of your former file style) and let a csv reader like Jackson do the parsing for you.

System.out.println does not work [duplicate]

This question already has answers here:
How to test for blank line with Java Scanner?
(5 answers)
Closed 7 years ago.
I am beginner in learning java programming. Basically, I can't make the last bit of my code to work. Before I show you my code, I think it is a good idea to show how the result should be. The result of the program should be:
Please Enter either S(supply) or R(replenish) followed by ID and quantity.
R p122. 10
New Stock-level for p122(Chain) is 58
S. p124. 20
New Stock-level for p125(Pedal) is 18
S. p905. 20
No part found with ID p905
.....// enter empty string to terminate
//Show final stock levels of all Parts
Although, I did be able to perform the main calculation and everything, I cannot print out the final stock levels of all Parts. I really don't understand why.
Here is my code:
import java.util.Scanner;
public class TestPart {
public static void main(String[] args) {
// Array of 5 Part objects
// Part[] part = new Part[5];
Part[] part = new Part[5];
part[0] = new Part("p122", "Chain", 48, 12.5);
part[1] = new Part("p123", "Chain Guard", 73, 22.0);
part[2] = new Part("p124", "Crank", 400, 11.5);
part[3] = new Part("p125", "Pedal", 3, 6.5);
part[4] = new Part("p126", "Handlebar", 123, 9.50);
///////// Test Class 2 ////////
Scanner scanner = new Scanner(System.in);
System.out.println("Please Enter either S (supply) or R (replenish) followed by ID and quantity.");
while (scanner.hasNext()) {
String sOrR = scanner.next();
String inputId = scanner.next();
int amount = scanner.nextInt();
for (int i = 0; i < 5; i++) {
String id = part[i].getID();
// Find ID in array
if (id.equals(inputId)) {
// S or R
if (sOrR.equals("R")) {
part[i].replenish(amount);
} else {
part[i].supply(amount);
}
System.out.println("New Stock-level for " + part[i].getID() + "(" + part[i].getName() + ") is "
+ part[i].getStockLevel());
}
}
if ((inputId.equals(part[0].getID()) == false) && (inputId.equals(part[1].getID()) == false)
&& (inputId.equals(part[2].getID()) == false) && (inputId.equals(part[3].getID()) == false)
&& (inputId.equals(part[4].getID()) == false)) {
System.out.println("No part found with ID " + inputId);
}
}
scanner.close();
System.out.println("Final stock level for all the parts: ");
for (int i = 0; i < 5; i++) {
System.out.println("Final Stock-level for " + part[i].getID() + "(" + part[i].getName() + ") is "
+ part[i].getStockLevel());
}
}
}
My program executes perfectly the calculating part. However it doesn't display final stocklevels.
Please Enter either S(supply) or R(replenish) followed by ID and quantity.
R p122. 10
New Stock-level for p122(Chain) is 58
S. p124. 20
New Stock-level for p125(Pedal) is 18
S. p905. 20
No part found with ID p905
Your abort condition (namely scanner.hasNext()) won't exit the while loop whenever the user enters an empty string. I don't know if you already noticed but whenever the user only hits the return key, nothing happens because Scanner.next does not trigger on return only. Though be aware that it stores your input. That means once you enter a "valid" input (such as abc), the Scanner will give you everything the user just entered before that valid input. Just a small example to demonstrate what I mean:
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
System.out.println("\"" + scanner.next() + "\"");
}
scanner.close();
System.out.println("finished");
So, if you want to abort your program after the user entered an empty line, this is not possible with java.util.Scanner.hasNext. I recommend you add another character to your "S or R" option that allows the user to exit the program like this:
if(sOrR.equals("E")) break;
You should place this directly behind String sOrR = scanner.next();.

For loop that prints from array

I am trying to print out two separate exam marks for students using a text file.
Below is a screenshot of the text file:
The first column is the student ID and the following two columns are both exam marks
Below is my code that does that calculations and prints:
//for loop that does calculations and prints
for(int i = 0; i < arraySize;i++){
String markOneFull = studentExamOneArray[i];
String markOneString = markOneFull.substring(5,7);
double markOne = Double.parseDouble(markOneString);
examOneNoID[i]= markOne;
String markTwoFull = studentExamTwoArray[i];
String markTwoString = markTwoFull.substring(8,10);
double markTwo = Double.parseDouble(markTwoString);
examTwoNoID[i] = markTwo;
/* String markThreeFull = studentExamThreeArray[i];
String markThreeString = markThreeFull.substring(5,10);
double markThree = Double.parseDouble(markThreeString);
examThreeNoID[i] = markThree;
String markFourFull = studentExamFourArray[i];
String markFourString = markFourFull.substring(5,10);
double markFour = Double.parseDouble(markFourString);
examFourNoID[i] = markFour;
*/
// Aggregate Mark
double aggregate = (examOneNoID[i] + examTwoNoID[i])/2;
DecimalFormat oneDigit = new DecimalFormat("#,##0.0");
//time to write
write.println(studentArray[i] + "\nAB101: " + examOneNoID[i] + " " + " AB102: " + examTwoNoID[i] + " Overall Mark: " + oneDigit.format(aggregate));
write.println("----------------------------------------");
}
write.close();
}
When i run the program i get an error message saying:
Exception in thread "main" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at MarksProcessing.main(MarksProcessing.java:42)
Try something like this:
Scanner sc = new Scanner(new File(fileName));
int i = 0;
while (sc.hasNext())
{
students[i] = sc.nextInt();
studentExamOneArray[i] = sc.nextDouble();
studentExamTwoArray[i] = sc.nextDouble();
double aggregate = (studentExamOneArray[i] + studentExamTwoArray[i])/2;
DecimalFormat oneDigit = new DecimalFormat("#,##0.0");
System.out.println("Student: " + students[i] + " FirstGrade: " + studentExamOneArray[i] + " SecondGrade: " + studentExamTwoArray[i] + " Overal: " + oneDigit.format(aggregate));
i++;
}
Now, you don't need substring and so on. You know the structure of file with grades or whatever that file is. And you don't need extra arrays (you use one for strings and then one for doubles and so on). Just read the numbers into array, then do the math and print.
I think, the specified problem can be easily handled . As we can see that here we are parsing string type into different kind of datatypes , so we should try to catch a Number Format exception.

Printing out line from CSV file that contains user input -

I have a program that allows the user to input observations into a CSV file and save them.
I want to be able to read the file and only print out observations that the user searches for. (ex. user types in "planet" and all lines containing planet are printed out. My current code prints out the whole file, and not just the specified lines. I'm having trouble setting up a logical statement to do this.
Here's my code:
void findbird() throws IOException{
Scanner input = new Scanner(System.in);
System.out.println("Please enter the type of bird you wish to search for");
String bird;
bird = input.next();
System.out.println("All observations of " + bird + "s:");
BufferedReader br = new BufferedReader(new FileReader("birdobservations.txt"));
String dataRow = br.readLine();
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase());
while (dataRow != null){
String[] dataArray = dataRow.split(",");
for (String item:dataArray) {
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
}
System.out.println();
dataRow = br.readLine();
}
br.close();
System.out.println();
menu();
}
My output currently looks like this:
Please enter the type of bird you wish to search for
Crow
All observations of Crows: Crow X Bergen May2015
Woodpecker M Oslo July2012
Hummingbird M Kaupanger December2015
Whereas I only want to print out:
Crow X Bergen May2015
There are a few problems.... the two most glaring are:
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase()); should surely be the other way around (dataRow...contains(...bird...))
You never reset the boolean variable contains so that it will print everything after it first is set to true... there has to be a contains = false somewhere
In general, you should probably have a loop that looks like:
String dataRow = null;
while ( (dataRow = scanner.readLine() ) != null) {
....
}
That way you do not need to do the silly readLine outside the loop as well, which makes your code cumbersome.
Once you have fixed up these code issues then come back again with an edited question.
This is the problem code
String dataRow = br.readLine();
boolean contains = bird.toLowerCase().contains(dataRow.toLowerCase());
while (dataRow != null){
String[] dataArray = dataRow.split(",");
for (String item:dataArray) {
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
}
Change it to
while((dataRow = br.readline())!= null)
{
//And now you get value of contain and then check if contain == true and add other piece of code
}
Your contains check is the wrong way around. The format is string.contains(substring).
contains should be moved inside the loop, otherwise you just set it once in the beginning, instead of for each row.
contains = true should be contains == true or simply contains. contains = true is assignment and will always return true, regardless of the value contains had.
Move the contains check outside the for-loop, otherwise it will print a message for each column in the row, not just once per row.
System.out.println(); will cause blank lines to be printed, if this is unwanted (it probably is), it should be removed.
Code:
while (dataRow != null){
boolean contains = dataRow.toLowerCase().contains(bird.toLowerCase());
String[] dataArray = dataRow.split(",");
if(contains){
for (String item:dataArray) {
System.out.print(item + "\t");
}
}
else
{
System.out.println("No observations of " + bird + " found!");
}
dataRow = br.readLine();
}
You have your logic backwards. Do:
boolean contains = dataRow.toLowerCase().contains(bird.toLowerCase());
Also, the fact that you have:
if(contains = true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}
means that contains will always be true, because you are assigning true to contains. You need to do:
if(contains == true){
System.out.print(item + "\t");
}else{
System.out.println("No observations of " + bird + " found!");
}

need help formatting strings in Java

I just started learning Java and I'm having trouble formatting string. In the problem I have a string a user inputted that is a name in the format: "First Middle Last". I need to output the string in the format: "Last, First MI. " (MI is middle initial).
Here is what I have so far, I have the first name working, but unsure how to go about getting the last and middle initial out of the string.
// Variable declarations
String name, first, last, middle;
Scanner scan = new Scanner (System.in);
// Get name from user in format "First Middle Last"
System.out.println("Enter the person's name: ");
name = scan.nextLine();
// Get first, middle initial, and last name from the string
first = name.substring(0, name.indexOf(" "));
middle =
last =
// Output formatted name as "Last, First MI."
System.out.println(last + ", " + first + " " + middle + ".");
so for example if the user entered: "John Robert Doe", it would output as "Doe, John R."
Any help is appreciated.
You can use the split method of the String class
// Get first, middle initial, and last name from the string
String nameParts [] = name.split(" ");
// not sure if you need these variables, but I guess you get the picture
first = nameParts [0];
middle = nameParts [1];
last = nameParts [2];
middleInital = middle.charAt(0);
// Output formatted name as "Last, First MI."
System.out.println(last + ", " + first + " " + middleInital + ".");
Take a look at the String.split method. This allows you to find the substrings. Then you only have to place them in the correct order
Take a look at String split and charAt method of String class.
String person_data = "John Robert Doe" ;
String[] data = person_data.split(" ");
char MI = data[1].charAt(0);
System.out.println(data[2] +","+ data[0] + " "+ MI);
Output = Doe,John R
Here
Data[0] == "John"
Data[1] == "Robert"
Data[2] == "Doe"
MI = first character of Data[1] which is R.
Try this:
String name = "First Middle Last";
String[] data = name.split(" ");
String formatted = String.format("%s, %s %c.", data[2], data[0], data[1].charAt(0));
The last line assigns the value "Last, First M." to the variable formatted, as expected. This solution makes use of Java's Formatter class, which is a big help for all your string formatting needs.
You will need to first split the string (using String.split) and then format it.
Forgive me since I'm typing this on my iPad, the answer will look as follows:
String names = name.split("\\s+"); \\Split on whitespaces, including tab, newline and carriage return.
StringBuilder sb = new StringBuilder();
for (int x = 0; x < names.length; x++) {
switch (x) {
case 0: sb.apppend(names[names.length - 1]).append(", ");
break;
case 1: sb.append(names[0]).append(" ");
break;
case 2: sb.append(Character.toUpperCase(names[1].charAt(0))).append(".");
break;
default: break;
}
}
String fullName = sb.toString();

Categories