KOB
KOB

Reputation: 4545

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:

  1. If the word being searched for happens to be the last word in the file then a "NoSuchElementException" is thrown.

  2. 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?

Upvotes: 3

Views: 1313

Answers (3)

RealSkeptic
RealSkeptic

Reputation: 34628

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.

Upvotes: 1

StackFlowed
StackFlowed

Reputation: 6816

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().

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726639

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.

Upvotes: 4

Related Questions