Why does one println statement change the entire output of my code? - java

Problem
I am currently creating a program to read a file and find a couple of variables. I am running into this problem where changing one println changes the entire output of my code. I have never run into this before and am not sure if this is an eclipse error or my error?
My Code
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class FileAnalyzer {
public static void main(String args[]) throws IOException {
Scanner input = new Scanner(System.in);
String fileName;
int words = 0, letters = 0, blanks = 0, digits = 0, miscChars = 0, lines = 0;
System.out.print("Please enter the file path of a .txt file: ");
fileName = input.nextLine();
File text = new File(fileName);
//System.out.println(text.exists());
Scanner word = new Scanner(text);
while(word.hasNext()) {
//System.out.println(word.next());
words++;
}
word.close();
Scanner letter = new Scanner(text);
while(letter.hasNext()) {
String currentWord = letter.next().toLowerCase();
for(int i = 0; i < currentWord.length(); i++) {
if(Character.isLetter(currentWord.charAt(i))) {
letters++;
}
}
}
letter.close();
Scanner blank = new Scanner(text);
while(blank.hasNextLine()) {
String currentWord = blank.nextLine();
for(int j = 0; j < currentWord.length(); j++) {
if (currentWord.charAt(j) == ' ') {
blanks++;
}
}
}
blank.close();
System.out.println("Words: " + words);
System.out.println("Letters: " + letters);
System.out.println("Blanks: " + blanks);
}
}
However
Simply changingSystem.out.println(word.next()) in the first Scanner instance changes the entire output. If i leave it in I get the three print statements at the bottom and what I am looking for. If I remove it since I do not want each word printed in the file it shows as nothing in the console. Not Sure why one print statement within a while statement changes the entire output.The only reason it was there in the first place was to make sure the scanner was taking input the way I had wanted.

Not Sure why one print statement within a while statement changes the entire output
Because when the statement is present, you're consuming a token from the scanner. When it's commented out, you're not. It's not the printing that consumes the token, it's the call to next().
With it commented out, your loop is:
while (word.hasNext()) {
words++;
}
hasNext() doesn't modify the state of the scanner, so that will just loop forever if it goes into the loop body at all.
If you want to have a line you can comment out or not, change the code to:
while (word.hasNext()) {
String next = word.next(); // Consume the word
System.out.println(next); // Comment this out if you want to
words++;
}

By using System.out.println(word.next()); you are cycling through the elements in a collection due to the next() method. So invoking next() directly will allow you to move through the iteration.
When commenting out //System.out.println(word.next());, then word.hasNext() will cause you to loop forever(provided there is a word) as you will not be able to move to the next token.
The below snippet will help you achieve your desired result
while(word.hasNext()){
word.next();
words++;
}

Not sure why you would want to go thru the text three times. But if you really have to, I would close the first scanner before opening the next.

Related

Java issues with Scanner and hasNextLine() while reading a file

I am having an issue with this unfinished program. I do not understand why this returns a "no Line found exception" when I run it. I have a while loop set up whose purpose is checking for this but I have done something wrong. I am trying to store information from a file into a 2d array for class.
import java.util.Scanner;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;
import java.util.Arrays;
public class LabProgram {
public static void main(String[] args) throws IOException {
Scanner scnr = new Scanner(System.in);
int NUM_CHARACTERS = 26; // Maximum number of letters
int MAX_WORDS = 10; // Maximum number of synonyms per starting letter
String userWord = (scnr.next()) + ".txt"; //Get word user wants to search
char userChar = scnr.next().charAt(0); //Get char user wants to search
String[][] synonyms = new String[NUM_CHARACTERS][MAX_WORDS]; // Declare 2D array for all synonyms
String[] words = new String[MAX_WORDS]; // The words of each input line
File aFile = new File(userWord);
Scanner inFile = new Scanner(aFile);
while(inFile.hasNextLine()) {
for(int i = 0; i < synonyms.length; i++) {
words = inFile.nextLine().trim().split(" ");
for(int wordCount = 0; wordCount < words.length; wordCount++) {
synonyms[i][wordCount] = words[wordCount];
}
}
}
}
}
The issue is with this for loop:
for (int i = 0; i < synonyms.length; i++) {
words = inFile.nextLine().trim().split(" ");
....
}
You're iterating from i=0 upto synonym.length-1 times, but that file does not have these much lines, so, as soon as your file is out of lines but the for loop has scope to iterate more, the inFile.nextLine() gets no line and thus throw the exception.
I don't know what you are exactly doing here or want to achieve through this code, but this is what causing you the trouble.
Hope that answers your query.
Basically your problem is that you're only checking hasNextLine() before the for loop starts, and you're actually getting the next line on every iteration of the loop. So if you run out of lines while in the middle of your for loop an exception is thrown.
I'm actually not quite sure what your code is supposed to do but at the very least you need to add a hasNextLine() check every time before you actually run nextLine() to avoid errors like this.

Palindrome parser logic error

I'm trying to create a program that parses through an input and determines whether or not it is a palindrome. Pasted below is my code so far:
import java.util.Scanner;
//Gets a message and shift amount and caesar shifts the message by the desired amount. Displays the enciphered message.
public class RobustPalChecker{
public static void main(String[] args){
//declare variables
char current, currentReverse;
int msgInt;
String msg, msgReverse;
StringBuffer sbMsg, newMsg;
Scanner sc = new Scanner(System.in);
//get message
System.out.println("Please enter an integer: ");
msg = sc.nextLine().toUpperCase();
//msgReverse = new StringBuffer(msg).reverse().toString();
System.out.println(msg);
//System.out.println("= " + msgReverse);
//get first and last index of string to check if it's a palindrome
for(int i = 0; i < msg.length(); i++) {
current = msg.charAt(i);
if(Character.isLetter(current) == false){
sbMsg = new StringBuffer(msg);
newMsg = sbMsg.deleteCharAt(i);
msgReverse = new StringBuffer(newMsg).reverse().toString();
}
}
if(newMsg.equals(msgReverse)) {
System.out.println("It's a palindrome");
}else {
System.out.println("It's not a palindrome");
}
}
}
Ignore comments as some of them don't apply and I have not cleaned it up yet. The line of code that I'm pretty sure is causing the error is the isLetter line. The goal of that loop is to find any character that is not a letter and just delete it, and that includes whitespace. That last if statement is the one that actually compares the reversed string and regular string. Now the output that the last if statement is giving me when I try to compile is "variable newMsg might not have been initialized" and the same for msgReverse, but that's not my main question.
My main question is: Is my logic here correct or incorrect?
Also, if you need me to rephrase the question, I can do that as I understand this might be hard to follow, I'm just panicking a little.
Your logic seems fine, but since code is not at all upto the mark its difficult to verify. I have written code in english commented format, if you are able to fill in the blanks all will fall in place.
Let's breakdown the problem in two sections :
Remove unwanted characters from string
Check if string returned from step1 is a pallindrome.
Create two functions :
String cleanUp(String arg){
//create a stringbuffer from arg
//start for loop
//delete unwanted chars from stringbuffer
//end loop
//make string from stringbuffer and return
}
boolean pallindrome(String arg){
//create a new string from arg reverse
//return true if reversed string and arg are same
}
Now call these functions from your main method.

Scanner & .hasNext() issue

I am new to Java and very new to the Scanner class. I am writing a program which asks the user for a word and then this word is searched for within a file. Each time the word is found, it is printed on a new line in a JOptionPane, as well as the word before and after it. Everything is functioning as it should, with two exceptions:
If the word being searched for happens to be the last word in the file then a "NoSuchElementException" is thrown.
If the word being searched for appears twice in a row (unlikely, but still a problem I discovered), it only returns it once. For example, if the word being searched for was "had" and "He said that he had had enough. He had been up all night" were sentences in the file, then the output is:
he had had
He had been
whereas it should be:
he had had
had had enough.
He had been
I believe that my problem lies in the fact that I use a while(scan.hasNext()) and within this loop I use scan.next() twice. I cannot find a solution for this though, while still achieving what I would like the program to return.
Here is my code:
//WordSearch.java
/*
* Program which asks the user to enter a filename followed
* by a word to search for within the file. The program then
* returns every occurrence of this word as well as the
* previous and next word it appear with. Each of these
* occurrences are printed on a new line when displayed
* to the user.
*/
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class WordSearch {
public static void main(String[] args) throws FileNotFoundException {
String fileName = JOptionPane.showInputDialog("Enter the name of the file to be searched:");
FileReader reader = new FileReader(fileName);
String searchWord = JOptionPane.showInputDialog("Enter the word to be searched for in \"" + fileName + "\":");
Scanner scan = new Scanner(reader);
int occurrenceNum = 0;
ArrayList<String> occurrenceList = new ArrayList<String>();
String word = "", previousWord, nextWord = "", message = "", occurrence, allOccurrences = "";
while(scan.hasNext()){
previousWord = word;
word = scan.next();
if(word.equalsIgnoreCase(searchWord)){
nextWord = scan.next();
if(previousWord.equals("")){
message = word + " is the first word of the file.\nHere are the occurrences of it:\n\n";
occurrence = word + " " + nextWord;
}
else{
occurrence = previousWord + " " + word + " " + nextWord;
}
occurrenceNum++;
occurrenceList.add(occurrence);
}
}
for(int i = 0; i < occurrenceNum; i++){
allOccurrences += occurrenceList.get(i) + "\n";
}
JOptionPane.showMessageDialog(null, message + allOccurrences);
scan.close();
}
}
Also, on a side note: How can I implement scan.useDelimeter() to ignore any, question marks, commas, periods, apostrophes etc?
If the word being searched for happens to be the last word in the file then a NoSuchElementException is thrown.
This is because of this line:
if(word.equalsIgnoreCase(searchWord)) {
nextWord = scan.next();
...
}
You do not check if the scan actually hasNext(), going straight for scan.next(). You can fix this by adding a conditional with a call to scan.hasNext()
If the word being searched for appears twice in a row (unlikely, but still a problem I discovered), it only returns it once.
That the same problem is in play here: when you find a word, you retrieve the next one right away.
Fixing this is a little tricky: you need to change your algorithm to look at one word at a time, and use previousWord (which you store anyway) for use of subsequent iterations of the while loop.
What you could do is just call hasNext before using next again.
while(scan.hasNext()){
previousWord = word;
word = scan.next();
if(word.equalsIgnoreCase(searchWord) && scan.hasNext()){ // this line change
nextWord = scan.next();
if(previousWord.equals("")){
message = word + " is the first word of the file.\nHere are the occurrences of it:\n\n";
occurrence = word + " " + nextWord;
}
else {
occurrence = previousWord + " " + word + " " + nextWord;
}
occurrenceNum++;
occurrenceList.add(occurrence);
}
}
You want to not use equals with ignore case. You want to just use .equals().
The solution would be to save two words the way you are currently saving previousWord. Something like:
while (scan.hasNext()) {
previousWord = word;
word = nextWord;
nextWord = scan.next();
Then you check word. If it matches what you need, then you can print it together with previousWord and nextWord. That is, in every iteration, you are checking the word you read in the previous iteration.
This way you only need one hasNext() and one next() in your loop.
Note that after the end of the loop, nextWord might actually be your word. This would mean your word is the last word in the file, and you should check for this and print it accordingly.

Why does my while loop needs this line of code to run?

I just completed an application which prompts the user for a text File input IO but I have something to clarify as the final part, While loop I actually managed to refer it to a tutorial on google. In this loop, there is a if-else statement and for the else part I don't understand why is it necessary.
Here's my code:
import java.io.*;
import java.util.*;
class FileReadingExercise2 {
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
Scanner fileInput = null;
do {
try {
System.out.println("Please enter the name of a file or type QUIT to finish");
String a = userInput.nextLine();
if (a.equals("QUIT")) { // if user inputs QUIT then stop application
System.exit(0);
}
fileInput = new Scanner(new File(a)); // the file contains text and integers
} catch (FileNotFoundException e) {
System.out.println("Error - File not found");
}
} while (fileInput == null);
int sum = 0;
while (fileInput.hasNext()) // continues loop as long as there is a next token
{
if (fileInput.hasNextInt()) // if there is an int on the next token
{
sum += fileInput.nextInt(); // then adds the int to the sum
} else {
fileInput.next(); // else go to the next token
}
}
System.out.println(sum);
fileInput.close();
}
}
As you can see, as long as the fileInput Scanner has a next token to look up to then operate the if else statement. If fileInput has a next Int then adds it up to the sum variable. So from what I think is that this will be sufficient. Once fileInput has no more token to read, it shall get out of the while loop isn't it? Why does it has still go onto the next token? I'm confused. Please advise thanks! ;)
Why does it has still go onto the next token?
That is because when nextInt() is executed it will consume the int number within the file but within it, it has a newLine character that needs to be consume and that is when next is executed to consume that newLine after the int number.
sample file content:
1
what actually in there is 1 character and newline \n character
In this loop, there is a if-else statement and for the else part I don't understand
why is it necessary.
fileInput.hasNexInt() method returns true if int value found and than it performs adding operation. if next value is not int type than else part will perform where fileInput.next() will return next value(pointer will points after that value), performs nothing means escaping next value(which can be any type except int-type). Again if condition will check for int.

Validating a LaTeX file, java

So I have this text file
\begin{document}
{\Large \begin{center} Homework Problems \end{center}}\begin{itemize}\item\end{itemize}
\begin{enumerate}
\begin{proof}
\begin{align}
\end{align}
\end{proof}
\begin{proof}
\begin{align}
\end{align}
\end{proof}
\end{enumerate}
\end{document}
And I want to go through each line, find all of the "\begin" pieces and then take the string with in the "{_}" and store it in a stack. When the corresponding "\end" is found, I call the pop() command on the Stack and remove it. I'm have a few issues though...
I'm running into dealing with all sorts of crazy cases and making sure everything is accommodated and its becoming too specific to this case when I want to make it work for all sorts of files that are written as such.
I don't know how to check for "\begin" and "\end" as opposed to "begin" and "end", the reason this is important is because if the file contains text that says "begins" or "end" it might not be a command and thus, not what I'm looking for.
All "if" statements DO NOT work on account of the "\" being present, I tried adding square brackets but it didn't fix anything.
Here is my code so far, and its getting really confusing, can anyone help organize and help rectify the issues I've stated above?
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Stack;
import java.util.StringTokenizer;
public class LaTeXParser{
public static void main(String args[]) throws FileNotFoundException{
Scanner scan = new Scanner(System.in);
Stack s = new Stack();
int lineCount = 0;
String line;
String nextData = null;
String title = null;
String fname;
System.out.print("Enter the name of the file (no extension): ");
fname = scan.next();
fname = fname + ".txt";
FileInputStream fstream = new FileInputStream(fname);
Scanner fscan = new Scanner(fstream);
System.out.println();
while(fscan.hasNextLine()){
lineCount++;
line = fscan.nextLine();
StringTokenizer tok = new StringTokenizer(line);
while(tok.hasMoreElements()){
nextData = tok.nextToken();
System.out.println("The line: "+nextData);
if(nextData.contains("\\begin") && !nextData.contains("\\end")){
if(nextData.charAt(1) == 'b'){
title = nextData.substring(nextData.indexOf("{") + 1, nextData.indexOf("}"));
s.push(title);
}
else{
//title = nextData.substring();
}
}//end of BEGIN if
if(nextData.contains("\\end") && !nextData.contains("\\begin")){
if(s.peek().equals(nextData.substring(nextData.indexOf("{") + 1, nextData.indexOf("}")))){
s.pop();
}
}//end of END if
if(nextData.contains("\\begin") && nextData.contains("\\end")){
String[] theLine = nextData.split("[{}]");
for(int i = 0 ; i < theLine.length ; i++){
if(theLine[i].equals("\\end") && theLine[i+1].equals(s.peek())){
s.pop();
}
if(theLine[i].equals("\\begin")){
title = theLine[i+1];
s.push(title);
}
}
}//end of BEGIN AND END if
}
}//end of whiles
fscan.close();
while(!s.isEmpty()){
System.out.println("the top "+s.pop());
}
}
}
EDIT: In the if statement that is used to check a line to see if it contains both a "\begin" and "\end" after finding the "\begin", how do I go back through to check if that line also contains it's "\end"? So I am talking about the case...
\begin{itemize}\item\end{itemize}
See I can get to the "\begin" and add the proper string, but it just moves and passes the "\end{itemize}". Anyway to fix this?
Actually it should check and perform normally even after the "itemize" string is pushed, but it doesn't work! I believe it has to do with "\end", can anyone confirm? It skips over that step, and obviously because it doesn't fit the conditions, but it works for the other lines. Just not this specific case!
You probably need to escape the backslashes, so write \\ instead of \. And if they are in regular expressions (regexprs) you need to escape them twice: \\\\ ; I don't think the brackets are needed.

Categories

Resources