Using hasNext() and If statements - java

I NEED your help in this. I am demanded to write a java code that reads data from a file. The data in the file looks like this:
88 73
13 60
16 20
59
9 45
44
If the line has only one number (like lines 4 and 6), it represents a Fahrenheit temperature that I need to convert into Celsius. If the line has two numbers, the second number represents relative humidity. I am stuck on how to read the data line by line and one by one. I managed so far to read all the data and put them in two strings that I will later on parse into int or double, but this only works if I have two numbers per line. I know I should use if statement to read if the line has one or two numbers, but I don't know how.
Here's my code
import java.util.*;
import java.io.*;
public class Test3 {
public static void main(String[] args) throws IOException{
FileInputStream file = null;
Scanner kb = null;
try{
file = new FileInputStream("test2.txt");
}
catch (FileNotFoundException e){
System.out.println("Critical error - could not open file");
System.exit(1);
}
kb = new Scanner(file);
while (kb.hasNext()){
String firstNum = kb.next();
String secondNum = kb.next();
System.out.println(firstNum);
System.out.println(secondNum);
}
}
}

Personally I would go for a readLine and split solution
kb = new Scanner(file);
while (kb.hasNextLine()){
String line = kb.nextLine();
String arr[] = line.split (" ");
for (String tok : arr) {
System.out.println(tok);
}
}

Related

Is there way a "reset" a scanner in Java?

Reset may not be the right word here, but I am currently building a program that lets the user look up a name, and by scanning a txt file containing a list of names followed by numbers, the program then displays the numbers following said name. The way I am doing this is via .nextLine, but if the user inputs a name that's later in the list (say Samantha in the example) and then tries to look up a name at the top of the list (like Sally), the second name isn't found.
For reference, here is an example of that txt file:
Sally 0 0 0 0 0 0 0 0 0 0 886
Sam 58 69 99 131 168 236 278 380 467 408 466
Samantha 0 0 0 0 0 0 272 107 26 5 7
Samir 0 0 0 0 0 0 0 0 920 0 798
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
public class BabyNames {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Scanner input = new Scanner (new File("BabyNames.txt"));
Scanner keyboard = new Scanner (System.in);
System.out.println("This program allows you to search through the data from the "
+ "Social Security Administration to see how popular a particular name has "
+ "been since 1900.");
System.out.print("Name? ");
String name = keyboard.nextLine();
do {
while(input.hasNextLine()) {
String text = input.nextLine();
String[] words = text.split(" ");
if (text.contains(name)) {
System.out.println("Statistics on name \"" + name + "\"");
for (int i = 1; i < words.length; i++) {
System.out.println((1900 + (i-1)*10) + ": " + words[i]);
}
System.out.println("Enter another name or type quit to exit.");
name = keyboard.nextLine();
break;
}
else if (name.contains("quit") || name.contains("quit")){
System.exit(0);
}
else {
continue;
}
System.out.print("Error, name not found.");
}
} while (!name.contains("quit") || name.contains("quit"));
}
}
I looked up the .reset method but that hasn't seemed to work. Honestly, I'm stumped here.
Again, don't try to "reset" the Scanner or re-read the file. Your best bet is to read the file once and place all the data into a collection of some type, here a Map<String, SomeCustomClass> would work best. I'd first create a class to hold a row of information, perhaps called BabyName, one that holds a String field for name and an Integer List for the numbers listed after the name, something like:
import java.util.*;
public class BabyName {
String name;
List<Integer> numberList = new ArrayList<>();
public BabyName(String name, List<Integer> numberList) {
this.name = name;
this.numberList = numberList;
}
public String getName() {
return name;
}
public List<Integer> getNumberList() {
return numberList;
}
#Override
public String toString() {
return "BabyName [name=" + name + ", numberList=" + numberList + "]";
}
// consider adding hashCode and equals methods that are based on the name field alone
// ...
}
And then I'd recommend in your code a method that takes a line of text that has been extracted from the file, and converts it into a BabyName object:
private static BabyName createBabyName(String line) {
String[] tokens = line.split("\\s+");
String name = "";
List<Integer> numberList = new ArrayList<>();
// ... code to extract the data and that fills the numberList here
// ... left blank for you to fill in
BabyName babyName = new BabyName(name, numberList);
return babyName;
}
And then create a Map<String, BabyName> babyNameMap = new HashMap<>(); to hold BabyName objects using the name field as the map key, and when you read the file (just once mind you), you fill the map:
Scanner fileScanner = null;
try {
fileScanner = new Scanner(new File(FILE_PATH_NAME));
} catch (FileNotFoundException e) {
e.printStackTrace();
System.exit(-1);
}
// read file and fill the map
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
BabyName babyName = createBabyName(line);
babyNameMap.put(babyName.getName(), babyName);
}
Then you can use this map to get the data from the user multiple times without having to re-read the file or reuse a Scanner.
e.g.,
String nameEnteredByUser = keyboard.nextLine();
BabyName selectedBabyName = babyNameMap.get(nameEnteredByUser);
// check for null here first
String name = nameEnteredByUser;
List<Integer> numberList = selectedBabyName.getNumberList();
Java Scanner, in general, doesn't know/control the pointer position in the file. It wraps over InputStream which in turn provides the input to the Scanner w.r.t every nextLine() call.
Scanner systemInput = new Scanner(System.in);
//new Scanner(new FileInputStream("file.t"));
InputStream has Mark/Reset feature which will help us to control the pointer position.
(Note: mark/ reset enables us to mark a checkpoint and you can jump back to the checkpoint later.)
Unfortunately, FileInputStream doesn't support it. But, BufferedInputStream came to the rescue.
Let's cook a solution for your problem,
Create a FileInputStream with your input file.
Wraps it with BufferedInputStream which provides mark() and reset() functions.
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("BabyNames.txt"));
Provide it as input to the Scanner constructor.
Scanner input = new Scanner (inputStream);
Mark a checkpoint at the beginning of the file.
inputStream.mark(0);//saving a checkpoint
After the end of the inner while loop, reset the pointer to the marked position.
inputStream.reset();
Now, your code works fine.

Number of elements in Periodic Table shows up as 0 and not 118

I need to output the number of elements from a dat file. The number of elements needs to be 118 but I get 0.
import java.io.*;
import java.util.Scanner;
public class PeriodicTable
{
public static void main(String[] args) throws IOException
{
final int MAX_ELEMENTS = 128;
int[] atomicNumber = new int[MAX_ELEMENTS];
File file = new File("periodictable.dat");
Scanner inputFile = new Scanner(file);
int currentElements = 0;
while(inputFile.hasNext())
{
atomicNumber[currentElements] = inputFile.nextInt();
String symbol = inputFile.next();
float mass = inputFile.nextFloat();
String name = inputFile.next();
currentElements++;
}
inputFile.close();
System.out.println("Periodic Table\n");
System.out.println(currentElements + " elements");
}
}
When I run the sample class it seems to work correctly for me, so I assume there is and issue with the periodictable.dat file.
With a test periodictable.dat file filled with the following:
110 T 200.00 Test
300 A 100.18 Again
I get the following output:
Periodic Table
2 elements
If there was a formatting error in the file you would receive a mismatch exception. So I would
Check your file is not empty as this would cause the while condition to be false.
I would also add what your current file looks like in your question :)

How can I get my scanner to read the next line in the file?

I am printing out the contents of a txt file while skipping over any numbers that are in the file.
The file I am using looks like this:
one two 3 three four
five six 7 eight
I have tried using input2.next() or input2.nextline() after System.out.print(token), but I either get an error or it doesn't read the next line accurately.
import java.util.*;
import java.io.*;
public class ScannerClass {
public static void main(String[] args) throws FileNotFoundException {
System.out.print("Enter file name and extension: ");
Scanner input = new Scanner(System.in);
File file = new File(input.next());
Scanner input2 = new Scanner(file);
String token;
//this will print out the first line in my txt file, I am having trouble
//reading the next line in the file!
while ((token = input2.findInLine("[\\p{Alpha}\\p{javaWhitespace}]+")) != null) {
System.out.print(token);
}
}
}
The output is:
one two three four
What I would like to see is the whole txt file less any numbers such as:
one two three four
five six eight
One main problem with your reg exp is that it matches only one part of the line first before the digit and then after the digit while the findInLine somehow advances the line counter.
So here is a different solution using your reg exp pattern but I have separated the reading from the file from the matching logic
Pattern p = java.util.regex.Pattern.compile("[\\p{Alpha}\\p{javaWhitespace}]+");
while (input2.hasNextLine()) {
String line = input2.nextLine();
Matcher m = p.matcher(line);
while (m.find()) {
System.out.print(m.group()); //Prints each found group
}
System.out.println();
}
You can add this RegEx;
import java.util.*;
import java.io.*;
public class ScannerClass {
public static void main(String[] args) throws FileNotFoundException {
System.out.print("Enter file name and extension: ");
Scanner reader = new Scanner(System.in);
reader = new Scanner(new File(reader.next()));
Pattern p = Pattern.compile("[a-zA-Z_]+");
Matcher m = null;
while (reader.hasNext()){
String nextLine = reader.nextLine();
m = p.matcher(nextLine);
while(m.find()) {
System.out.printf("%s ",m.group());
}
System.out.println();
}
}
}
May not be the most optimum but it'll work. Each loop iteration will split the current line into an array of strings delimited by a number (\\d+), then each array element (the alphabet words and whitespace in this case) will be streamed and joined into a single string.
while (input2.hasNextLine()) {
String[] nonNumbers = input2.nextLine().split("\\d+");
System.out.println(Arrays.stream(nonNumbers).collect(Collectors.joining()));
}

Reading multiple integers in multiple lines

I am currently writing my Bachelor's thesis in graph theory and use the java scanner to convert a txt file with edges into my Java class graph. My txt file looks like this:
1 2 72 3
2 3 15 98
4 7 66 49
5 6 39 48
6 9 87 97
8 13 31 5
The ints are ordered as: source vertex, sink vertex, cost, capacity.
My Code looks like:
Graph graph = new Graph(false);
File f = new File("Filepath");
Scanner in = new Scanner(f);
while (in.hasNextLine())
{
for (int i =1; i<= numberEdges; i++)
{
String s = in.nextLine();
try (Scanner inscan = new Scanner(s)) {
while (inscan.hasNext())
{
int source = inscan.nextInt();
int sink = inscan.nextInt();
double cost =inscan.nextDouble();
double capacity = inscan.nextDouble();
Vertex Source = new Vertex(source);
Vertex Sink = new Vertex(sink);
Edge edge = new Edge(Source,Sink, cost, capacity);
graph.addEdge(edge);
}
}
}
}
in.close();
I tried to scan each line in a String and then scan the String into my Variables.
It always throws a "NoLineFound" Exception in the first line of the for loop and if I try it with outputing the lines I get none. But when I disable the second scanner and try again I get all lines in the ouput but at the end still a "NoLineFound" Exception.
I checked my txt File and the last line doesn't have a UTF8 line ending, but I don't know how to give it one.
I think that your problem comes from that :
while (in.hasNextLine()){
for (int i =1; i<= numberEdges; i++)
{
First, iteration is redundant (while or for are unitary enough for reading each line. You have to do choice between them).
Besides if your file has less line than numberEdges, a java.util.NoSuchElementException will be raised.
If the number of line is constant in the file, use a for:
for (int i =1; i<= numberEdges; i++)
remove the enclosing while (in.hasNextLine()). It is not required. Iteration control is already done by the for.
If the number of lines in the file may vary, use only a while :
while (in.hasNextLine()){
But anyway, don't use both.
With Java 8 streams:
Files
.lines(f.toPath())
.map(l ->Arrays.stream(l.split(" ")).mapToDouble(Double::parseDouble).toArray())
.map(a->new Edge(new Vertex((int)a[0]), new Vertex((int)a[1]), a[2], a[3]))
.forEach(graph::addEdge);
You are reading nextLine() in a loop after a single check for hasNextLine(). You need to perform a check after each read in order to avoid the "NoLineFound" exception.
It looks like the nested loop is completely unnecessary. You can read file line-by-line, ignoring empty lines, and build your graph without prior knowledge of the number of edges that it has:
Graph graph = new Graph(false);
File f = new File("Filepath");
Scanner in = new Scanner(f);
while (in.hasNextLine()) {
String s = in.nextLine();
try (Scanner inscan = new Scanner(s)) {
if (!inscan.hasNext()) {
continue; // Ignore empty lines
}
int source = inscan.nextInt();
int sink = inscan.nextInt();
double cost =inscan.nextDouble();
double capacity = inscan.nextDouble();
Vertex Source = new Vertex(source);
Vertex Sink = new Vertex(sink);
Edge edge = new Edge(Source,Sink, cost, capacity);
graph.addEdge(edge);
}
}
in.close();
Just perform a check after reading to avoid the "NoLineFound" exception.
You can use the below code to scan the file:
import java.io.File;
import java.util.Scanner;
public class ReadFile {
public static void main(String[] args) {
try {
System.out.print("Enter the file name with extension : ");
Scanner input = new Scanner(System.in);
File file = new File(input.nextLine());
input = new Scanner(file);
while (input.hasNextLine()) {
String line = input.nextLine();
System.out.println(line);
}
input.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Java input return incorrect values [duplicate]

This question already has answers here:
System.in.read() method
(6 answers)
Closed 8 years ago.
I use this official example to receive input from the user and then print it:
import java.io.IOException;
public class MainClass {
public static void main(String[] args) {
int inChar;
System.out.println("Enter a Character:");
try {
inChar = System.in.read();
System.out.print("You entered ");
System.out.println(inChar);
}
catch (IOException e){
System.out.println("Error reading from user");
}
}
}
The problem, It always returns incorrect values. For example, When enter 10 it returns 49 while I expect to return 10!
What is the reason for this issue and how could I solve it.
This returns the int value of a character, if you want to print the character cast it to char:
System.out.println((char) inChar);
This will only print the value of the first character that was input because System.in.read() only reads the first byte.
To read a whole line you could use a Scanner:
import java.util.Scanner;
public class MainClass {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Write something:");
// read input
String line = scanner.nextLine();
System.out.print("You entered ");
System.out.println(line);
}
}
Try this snippet.
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader brInput = new BufferedReader(isr);
String strInput = brInput.readLine();
System.out.println("You wrote "+strInput);
System.in.read reads only first byte from input stream
So if you enter
123
the first character is 1.So its corresponding ASCII is 49
If we enter
254
the first character is 2.So its corresponding ASCII is 50
Edit:This is explained also here

Categories

Resources