Adam
Adam

Reputation: 61

Searching and Counting Word Fragments in a text file

I was tasked with writing a code that opens a text file, then searches for occurrences of the user's string in the text file and reports how many there were.

The code is below for what I have. It will search for word fragments, which is good, but the professor want it to search for bizzare fragments that have spaces and everything. Something like "of my" or "even g" or any other arbitrary string of characters.

My working code is below, I've been trying to make compareTo work, but I can't seem to get the syntax down. This professor insists on not being helpful and it's a summer class so not TA's to help. I've googled to no avail, it seems I can't put the problem into a decent set of word to search for.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

import javax.swing.*;

public class TextSearchFromFile 
{
public static void main(String[] args) throws FileNotFoundException 
{

    boolean run = true;
    int count = 0;


            //greet user
        JOptionPane.showMessageDialog(null, 
                "Hello, today you will be searching through a text file on the harddrive. \n"
                + "The Text File is a 300 page fantasy manuscript written by: Adam\n"
                + "This exercise was intended to have the user enter the file, but since \n"
                + "you, the user, don't know which file the text to search is that is a \n"
                + "bit difficult.\n\n"
                + "On the next window you will be prompted to enter a string of characters.\n"
                + "Feel free to enter that string and see if it is somewhere in 300 pages\n"
                + "and 102,133 words. Have fun.", 
                "Text Search", 
                JOptionPane.PLAIN_MESSAGE);

    while (run)
    {
        try
        {
                //open the file
            Scanner scanner = new Scanner(new File("An Everthrone Tale 1.txt"));

                //prompt user for word
            CharSequence findWord = JOptionPane.showInputDialog(null, 
                    "Enter the word to search for:", 
                    "Text Search", 
                    JOptionPane.PLAIN_MESSAGE);
            count = 0;


            while (scanner.hasNext())
            {

                if ((scanner.next()).contains(findWord))
                {
                    count++;
                }

            } //end search loop


                //output results to user
            JOptionPane.showMessageDialog(null, 
                    "The results of your search are as follows: \n"
                    + "Your String: " + findWord + "\n"
                    + "Was found: " + count + " times.\n"
                    + "Within the file: An Ever Throne Tale 1.txt", 
                    "Text Search",
                    JOptionPane.PLAIN_MESSAGE);
        } //end try
        catch (NullPointerException e)
        {
            JOptionPane.showMessageDialog(null, 
                    "Thank you for using the Text Search.", 
                    "Text Search", 
                    JOptionPane.ERROR_MESSAGE);
            System.exit(0);
        }
    } //end run loop
} // end main
} // end class

Just at a loss of how to make it search for crazy arbitrary pieces like that. He knows whats in the text file so he knows he can put sequences together like my examples above that can be found within the text, but they are not.

Upvotes: 1

Views: 1272

Answers (2)

David Conrad
David Conrad

Reputation: 16359

Don't use hasNext() and next() since those will only return a single token at a time from the input file, and you won't be able to find a multi-word phrase (or anything containing spaces). If you use hasNextLine() and nextLine() you can do a little better, but it still won't find cases where "of my" appears with "of" as the last word on one line, and "my" as the first word on the next line. To find that, you need a little more context.

If you keep track of the last line read from the file, you can create a two-line buffer and find instances that are spread across multiple lines.

String last = ""; // initially, last is empty

while (scanner.hasNextLine())
{

    String line = scanner.nextLine();
    String text = last + " " + line; // two-line buffer

    if (text.contains(findWord))
    {
        count++;
    }

    last = line; // remember the last line read

} //end search loop

This should find words broken across two lines, but there are still three problems. First, you could have a phrase like "three lines long" that is broken across three lines:

  three
  lines
  long

You would need to extend the two-line buffer concept to find this. Ultimately, you might need to have the entire file in memory at once, but I suspect that is enough of an edge case that you probably don't care about it.

Second, when words are found on a single line, you will count them twice. Once when the word first appears on the line being read, and a second time when it is in the last line, the previous time it has been read.

Third, using contains in this way won't find multiple copies of the same word on the same line. So if you are looking for "dog" and the following text appears:

  My dog saw a dog today at the dog park which was full of dogs.

The test with contains will only cause count to be incremented once. (But it would happen again when this line was in last.)

So I think you really need to 1. Read the entire file into a buffer, to find phrases split across any number of lines, and 2. Search through the lines using indexOf with an offset that increases until no more matches are found.

String text = "";

if (scanner.hasNextLine())
{
    text += scanner.nextLine(); // first line
}
while (scanner.hasNextLine())
{
    text += " "; // separate lines with a space
    text += scanner.nextLine();
}

int found, offset = 0; // start looking at the beginning, offset 0
while ((found = text.indexOf(findWord, offset)) != -1)
{
    count++; // found a match
    offset = found + 1; // look for next match after this match
}

If you don't care about matches broken across multiple lines, then you can do it one line at a time and avoid the memory cost of having the entire text in memory at once.

Upvotes: 1

ND27
ND27

Reputation: 437

Do something on the lines of -

  1. Get the string as it is. Dont split it by space or anything.
  2. use the indexOf on the string. Once a match has been found, start from the place

    int index = word.indexOf(guess); while (index >= 0) { System.out.println(index); index = word.indexOf(guess, index + 1); }

Indexes of all occurrences of character in a string

Upvotes: 0

Related Questions