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.
Related
How do I print only the first letter of the first word and the whole word of the last? for example,
I will request username input like "Enter your first and last name" and then if I type my name like "Peter Griffin", I want to print only "P and Griffin". I hope this question make sense. Please, help. I'm a complete beginner as you can tell.
Here is my code:
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
System.out.println("Enter your first and last name");
String fname=scan.next();
}
The String methods trim, substring, indexof, lastindexof, and maybe split should get you going.
This should do the work (typed directly here, so syntax errors might be there)
String fname=scan.nextLine(); // or however you would read whole line
String parts=fname.split(" ");
System.out.printf("%s %s",parts[0].substring(0,1),parts[parts.length-1]);
What you have to do next:
Check if there actually at least 2 elements in parts array
Check if first element is actually at least 1 char (no empty parts)
Check if there is actually line to read
Do your next homework yourself, otherwise you will not anything
I recommand you to watch subString(1, x) and indexOf(" ") to cut from index 1 to first space.
or here a other exemple, dealing with lower and multi name :
String s = "peter griffin foobar";
String[] splitted = s.toLowerCase().split(" ");
StringBuilder results = new StringBuilder();
results.append(String.valueOf(splitted[0].charAt(0)).toUpperCase() + " ");
for (int i = 1; i < splitted.length; i++) {
results.append(splitted[i].substring(0, 1).toUpperCase() + splitted[i].substring(1)+" ");
}
System.out.println(results.toString());
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.
I'd like to just see an example with some explanation.
What string functions do I use to compare the objects and does it compare each character or the actual word without any additional letters to it?
Thanks
I tried doing something very similar to this question for a project awhile ago. There are numerous ways to do this in Java, but I used the Scanner class and the File class.
public static void main(String[] args)
{
Scanner input = new Scanner(System.in); //Just a normal scanner
System.out.println("Please enter in the pathname to the file you want to view.");
String pathname = input.nextLine(); //Pathname to text file
File book = new File(pathname); //Creating a new file using the pathname
if(book.canRead() == false) //If Java cant read the file, this will pop up
{
System.out.println("Your file cannot be read");
}
else if(book.canRead() == true) //If Java can read the file, then this asks for the word to search for
{
System.out.println("Please enter in the word you wish to search for.");
wordToSearchFor = input.nextLine();
wordCounter(book); //Calls the method
}
System.out.println(wordToSearchFor.toLowerCase() + " appeared " + numOfOccurrences + " times in " + pathname);
}
This is the main method where you use the File class to create a file based off of a pathname that you give it EX - C:\Users\alex\Downloads\mobydick.txt
I then check to see if you can read the file, and if you can, then I call a method to analyze the book itself
import java.io.*;
import java.util.Scanner;
public class TextReader
{
private static int numOfOccurrences; //Counter to keep track of the number of occurances
private static String wordToSearchFor; //String field so both methods can access it
/*
* This method takes in the file of the book so the scanner can look at it
* and then does all of the calculating to see if the desired word appears,
* and how many times it does appear if it does appear
*/
public static void wordCounter(File bookInput)
{
try
{
Scanner bookAnalyzer = new Scanner(bookInput); //Scanner for the book
while(bookAnalyzer.hasNext()) //While the scanner has something to look at next
{
String wordInLine = bookAnalyzer.next(); //Create a string for the next word
wordInLine = wordInLine.toLowerCase(); //Make it lowercase
String wordToSearchForLowerCase = wordToSearchFor.toLowerCase();
String wordToSearchForLowerCasePeriod = wordToSearchForLowerCase + ".";
if(wordInLine.indexOf(wordToSearchForLowerCase) != -1 && wordInLine.length() == wordToSearchFor.length())
{
numOfOccurrences++;
}
else if(wordInLine.indexOf(wordToSearchForLowerCasePeriod) != -1 && wordInLine.length() == wordToSearchForLowerCasePeriod.length())
{
numOfOccurrences++;
}
}
}
catch(FileNotFoundException e) //Self explanitory
{
System.out.println("The error is FileNotFoundException - " + e);
System.out.println("This should be impossible to get to because error checking is done before this step.");
}
}
Scanners in Java can be take a File object to analyze, which is the fist thing I do in this method. I then use a while loop and ask the Scanner if there is a word that follows the current word. As long as there is a word, this will continue to run. I then create a String of the current word that the scanner is on to use as a reference to compare against. I then use a method that comes with the String class to make everything lowercase because uppercase and lowercase letters matter.
The first if statement in this method checks if the current word that the scanner has matches what you are searching for using the indexOf method from the String class, which takes some string and looks to see if it exists in another string. The if statement comparison also makes sure that the desired word length is the same as the word length in the book in case you are looking up "the" and it doesnt mark "then" as a word since it contains "the". The second if statement does the same thing, just with your desired word with a period at the end. If you wanted to go the extra mile, you could also check for exclamation points, question marks, commas, and so forth, but I decided to just check for periods.
Every time one of these if statements is correct, I increment a variable by one, and after the scanner runs out of words to search for, I print out the total number of times that certain word appears in a text file.
This program will read each phone number from the telephones.txt file and will check if it can be translated into one or more words of words.txt file. The output of the program will contain the telephone numbers and their word representatives. (assuming there are words and phones in the file)
public static void main(String[] args) throws IOException
{
Scanner phones = new Scanner(new File("phones.txt"));
Scanner words = new Scanner(new File("words.txt"));
PrintWriter outfile = new PrintWriter(new FileWriter("outfile.txt"));
String number = "", output = "", code = "" ;
//Scans for next phone string
while(phones.hasNext())
{
number = phones.next();
number = number.replace("-","");
//Scans for next word string
while(words.hasNext())
{
code = words.next();
char[] wordChars = null;
wordChars = code.toCharArray();
output = "";
//converts word to digits
for(char wordChar : wordChars)
{
output = output.concat(new String(convert(wordChar)));
}
if(number.equals(output));
{
System.out.println(number + " " + code);
}
break;
}
}
}
This is what I have done so far, except I can't figure out something
if(number.equals(output));
{
System.out.println(number + " " + code);
}
For this line Im trying to see if the output has the same value as the number and if it does have the same value I want to print it out however this is what happens in my program.
I tried tracing my program and this is what i think is happening but its not...
Enter first while loop while theres a phone string continue
Set number to next phone string
Enter 2nd while loop while theres a word string continue
Set code to the CURRENT word string and convert it to a digit value (assume the conversion is correct)
If converted string isn't equal to number I want to continue the loop and search for the next word. And if it is I want to display number + code and continue searching for more words.
After i search through the list of words I want to continue to the next number and repeat the search for words for that number until the first while loop has no more numbers
Answering your second issue:
After i search through the list of words I want to continue to the
next number and repeat the search for words for that number until the
first while loop has no more numbers
Answer:
You should create a new instance if scanner in each iteration, i.e. move the line:
Scanner words = new Scanner(new File("words.txt"));
into the body of the outer loop.
while(phones.hasNext())
{
Scanner words = new Scanner(new File("words.txt"));
number = phones.next();
number = number.replace("-","");
//Scans for next word string
while(words.hasNext())
{
...
}
}
Your inner loop always ends on a break. So the loop body will only ever get executed once. Just put your break into the block that describes the handling of a successful phone number match.
I was wondering if someone can tell me why my while loop is acting funny. When I input a 3 word phrase it should create an acronym. For a reason beyond my java understanding the while loop executes but then keeps executing even when the client inputs the right answer. Any idea why? I have read what seems million posts and watch youtube videos about it, but no clue.
import javax.swing.*;
import java.util.*;
public class ThreeLetterAcronym
{
public static void main(String args[])
{
//variables
String phrase;
int wordCount;
String acronym;
//input
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase.");
String [] word = phrase.split("\\s+");
wordCount = word.length;
//loop for error when less than 3 words
do
{
JOptionPane.showMessageDialog(null, "Error, you need to input a 3 word phrase to create a 3 letter acronym." + '\n'
+ "Please try again.");
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase");
}
while(wordCount !=3);
//create acronym
acronym = Character.toString(word[0].charAt(0)).toUpperCase() +
Character.toString(word[1].charAt(0)).toUpperCase() +
Character.toString(word[2].charAt(0)).toUpperCase();
//output
JOptionPane.showMessageDialog(null, "The phrase you inputed is " + "."
+ phrase + "\nYour 3 letter acronym is " + acronym + ".");
}
}
enter code here
Your loop will fail if the user types 4 or more words. Change wordCount != 3 to wordCount < 3 or be ready to handle longer phrases like North Atlantic Treaty Organization.
A do-while loop always executes at least once. Here, where you are checking for errors, that's actually reasonable, but you are also never recalculating your word array, so the error condition persists. You want logic like:
String[] words; // words, not word. There is more than one.
while (true) {
// 1. Fill in the word array from the user's input.
// 2. Check the input for errors.
// a. If there are none, break out of the loop with a break statement.
// b. Otherwise, show the error message.
}
// Create the acronym. Try to use a loop for this too, as in:
StringBuilder acronym = new StringBuilder();
for (String word: words) {
// Append to acronym.
}
// report acronym.
Finally, try not to do all your work in main. Create a ThreeLetterAcronym object, give it instance variables and methods, and tell it to do the work. Break up the work in main into smaller methods. Now, you can test those methods.
Your loop is executing after entering a three-word phrase because, as Eric mentioned, a 'do-while' loop will always execute at least once. The best, simple solution to resolve that issue would be to use a while loop instead, as follows:
while(wordCount != 3)
{
JOptionPane.showMessageDialog(null, "Error, you need to input a 3 word phrase to create a 3 letter acronym." + '\n'
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase");enter code here
}
A do-while loop performs an action and then checks if it should perform that action again. A while loop checks if it should perform an action first, which is what you want to be doing.
There are also some other significant issues that would be worth resolving at the same time.
Your variables word and wordCount are not being updated once the program enters your do-while loop. If a user first enters a three-word phrase, they're fine. If they enter a phrase of any other length the program will loop indefinitely. Since the program is executing the logic inside the do-while loop only, and that does not include saving new words into the variable word or figuring their length an dstoring it in wordCount, there is no way to exit the loop.
As a quick fix I added these two lines to solve those issues:
word = phrase.split("\\s+");
wordCount = word.length;
You could also eliminate the wordCount variable entirely by checking, but I'm honestly not sure if there's value in doing that versus having the variable in use. phrase.split("\\s+").length in the while loop.
Your main problem is that your loop will never terminate; wordCount is not being updated inside of your do...while block.
Your next problem is that a do...while loop always runs at least once.
What you can do to fix this issue is move another instantiation of word into your loop body, remove the unnecessary wordCount variable (since it's a property of the array, and we only need it in one spot), and change your do...while to a while.
//input
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase.");
String[] word = phrase.split("\\s+");
//loop for error when less than 3 words
while(word.length < 3) {
JOptionPane.showMessageDialog(null, "Error, you need to input a 3 word phrase to create a 3 letter acronym." + '\n'
+ "Please try again.");
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase");
word = phrase.split("\\s+");
}
Solved
use this code -
import javax.swing.*;
public class ThreeLetterAcronym
{
public static void main(String args[])
{
//variables
String phrase;
int wordCount;
String acronym;
//input
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase.");
String [] word = phrase.split(" ");
wordCount = word.length;
//loop for error when other than 3 words
while(wordCount!=3)
{
JOptionPane.showMessageDialog(null, "Error, you need to input a 3 word phrase to create a 3 letter acronym." + '\n'
+ "Please try again.");
phrase = JOptionPane.showInputDialog(null, "Please enter a three word phrase");
}
//create acronym
acronym = Character.toString(word[0].charAt(0)).toUpperCase() +
Character.toString(word[1].charAt(0)).toUpperCase() +
Character.toString(word[2].charAt(0)).toUpperCase();
//output
JOptionPane.showMessageDialog(null, "The phrase you inputed is " + "."
+ phrase + "\nYour 3 letter acronym is " + acronym + ".");
}
}