Sunday, July 2, 2017

Programming Challenge 12.6 - String Search

Example-File: short.txt
Include-File: UtilityCls.h


/* String Search - This program asks the user for a file name and a string
    to search for. The program searches the file for every occurrence of a
    specified string. When the string is found, the line that contains it is
    displayed. After all the occurrences have been located, the program reports
    the number of times the string appeared in the file. */

#include "UtilityCls.h"

struct GetFile
{
    string fileName;        /* The file name    */
    fstream textFile;        /* fstream object */

    GetFile(string fName = "")
    {
        fileName = fName;
    }

    ~GetFile()
    {
    }
};

struct TextSearch
{
    int    timesFound;        /* Counts the occurrences of words found in the text        */
    string searchWord;        /* Holds the word to search for in the text                    */
    string delimList;            /* Holds a list of delimiting characters                        */
    string tmpText;            /* A temporary variable to hold text while it is read in */
    string getText;            /* Holds the text read in from the file                        */
    string searchResult;        /* Holds the search result                                            */

    TextSearch(int cnt = 0, string dlmLst = ".:)(!?\";,", string sw = " ",
                string gTxt = " ", string sRes = " ")
    {
        timesFound = cnt;
        searchWord = sw;
        delimList = dlmLst;
        getText = gTxt;
        searchResult = sRes;
    }

    ~TextSearch()
    {
    }
};

void menu(GetFile &, TextSearch &);
char tryAgain();
void getFileName(GetFile &);
int  openFile(GetFile &, TextSearch &);
void getSearchWord(TextSearch &);
void changeCase(TextSearch &);
void removePunct(TextSearch &);
void performTextSearch(TextSearch &, const string);
void getWordFreq(TextSearch &);
void displayResult(const TextSearch &);
void cleanUp(GetFile &, TextSearch &);

int main()
{
    GetFile fileData;
    TextSearch search;
   
    menu(fileData, search);

    pauseSystem();
    return 0;
}

/* **********************************************************
    Definition: menu

    This function uses a two structure reference parameters.
    It offers a basic menu and introduction to the program.
    ********************************************************** */

void menu(GetFile &fileData, TextSearch &search)
{
    int  fOpen = 0;
    char again = ' ';

    cout << "\n\tText Search\n\n"
          << "\tThis program allows you to search for a word\n"
          << "\tin any given text-file. It will only find whole\n"
          << "\twords. To give you an example, if you type in the\n"
          << "\tword 'is', it will only find and display this word\n"
          << "\tand sentences that contain it. If 'is' is part of\n"
          << "\tanother word, like 'this', it will not be found.\n\n";

    do
    {
        fOpen = openFile(fileData, search);

        if (fOpen != -1)
        {
            cout << "\n\n\tText Search - Search Result\n\n";
            displayResult(search);
        }

        again = tryAgain();

        if (again == 'N')
        {
            cout << "\n\tThank you for trying this program!";
        }
        else
        {
            clearScreen();
            cleanUp(fileData, search);
        }
    } while (again != 'N');
}

/* **********************************************************
    Definition: openFile

    This function uses a two structure reference parameters as
    its arguments. First, the user is asked to enter a file
    name. If the file exists and is opened successfully, the
    user is asked to enter a word to search for. Then the file
    contents is read in and processed by other functions,
    while the text is being read-in. In case of an error, an
    error message is displayed, and the function exits.
    ********************************************************** */

int openFile(GetFile &fileData, TextSearch &search)
{
    string tmpText = "";

    getFileName(fileData);

    while (fileData.fileName.empty())
    {
        cin >> fileData.fileName;
    }

    /* Open the file for reading */
    fileData.textFile.open(fileData.fileName, ios::in);

    if (!fileData.textFile.fail())
    {
        getSearchWord(search);

            while (getline(fileData.textFile, tmpText))
            {       
                search.getText = ' ' + tmpText + ' ';

                removePunct(search);
                changeCase(search);
                performTextSearch(search, tmpText);
                getWordFreq(search);
            }
    }
    else
    {
        cout << "\tFile open error: " << fileData.fileName
              << " could not be openend.";
        return -1;
    }
    fileData.textFile.close();

    return 0;
}

/* **********************************************************
    Definition: getSearchWord

    This function uses a structure reference parameter. The
    user is asked to enter a word to search for. If the word
    contains uppercase letters, they are changed to lowercase.
    This allows to search for 'Pac-man' as well as 'pAc-Man'
    or any other variation of casing letters.
    ********************************************************** */

void getSearchWord(TextSearch &search)
{
    cout << "\tPlease enter a word to search for: ";
    cin >> search.searchWord;

    while (search.searchWord.empty() || search.searchWord == "\0")
    {
        cout << "\tPlease enter a word to search for: ";
        cin >> search.searchWord;
    }

    for (size_t i = 0; i < search.searchWord.size(); i++)
    if (isupper(search.searchWord.at(i)))
    {
        search.searchWord.at(i) = tolower(search.searchWord.at(i));
    }
}

/* **********************************************************
    Definition: getFileName

    This function uses a structure reference as parameter. It
    asks the user for a filename. If the filename does not
    contain a file-extension, for example '.txt', it is added,
    and the filename stored in a struct member variable. If a
    file-extension has been entered, the filename is stored,
    and the function exits.
    ********************************************************** */

void getFileName(GetFile &getName)
{
    string fileExt = ".txt";

    cout << "\n\tPlease enter a file name: ";
    cin >> getName.fileName;

    if (getName.fileName.find(".") != string::npos)
    {
        getName.fileName;
    }
    else
    {
        getName.fileName.append(fileExt);
    }
}
/* **********************************************************
    Definition: changeCase

    This function uses a structure reference parameter. It
    turns all uppercase letters found in a text to lowercase.
    ********************************************************** */

void changeCase(TextSearch &search)
{
    for (int i = 0; i < search.getText.size(); i++)
    {
        search.getText[i] = tolower(search.getText[i]);
    }
}

/* **********************************************************
    Definition: removePunct

    This function uses a structure reference parameter. It
    finds and removes selected punctuation characters. Once
    done, the text stored in a structure member variable.
    ********************************************************** */

void removePunct(TextSearch &search)
{
    for (int i = 0; i < search.delimList.size(); i++)
    {
        search.getText.erase(remove(search.getText.begin(), search.getText.end(),
                                             search.delimList.at(i)), search.getText.end());
    }
}

/* **********************************************************
    Definition: performTextSearch

    This function uses a structure reference parameter and a
    string object holding the unprocessesed text. It searches
    for the occurence of the word. If a match is found, the
    sentence(s) containing it are stored in the appropriate
    structure member variable.
    ********************************************************** */

void performTextSearch(TextSearch &search, const string tmpText)
{
    if (search.getText.find(' ' + search.searchWord + ' ') != string::npos)
    {
        search.searchResult.append("\t" + tmpText + "\n");
    }
}

/* **********************************************************
    Definition: getWordFreq

    This function uses a structure reference variable as its
    argument. It contains a stringstream object, which, word
    by word, extracts the text from a struct member variable
    holding the full text. It searches for an occurence of the
    word input by the user. If a match is found, a counter,
    which is another struct member variable, increments.
    ********************************************************** */

void getWordFreq(TextSearch &search)
{
    stringstream ss(search.getText);

    while (ss >> search.getText)
    {
        if (search.getText == search.searchWord)
        {
            ++(search.timesFound);
        }
    }
}

/* **********************************************************
    Definition: displayResult

    This function uses a constant structure reference variable
    as its argument. If the word to be searched for has been
    found, the word, the sentence(s) contaninig this word, and
    the number of matches is displayed. If there is no match,
    the user is informed by a message about the fact.
    ********************************************************** */

void displayResult(const TextSearch &search)
{
    if (search.timesFound != 0)
    {
        cout << "\n\tYour search word: " << search.searchWord << " was found "
            << search.timesFound << " times.\n";

        cout << "\n\tThe following sentence(s) contain this word:\n\n"
            << search.searchResult;
    }
    else
    {
        cout << "\n\tNo match found for your search word: " << search.searchWord;
    }
}

/* **********************************************************
    Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
    ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to perform another search? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to perform another search? ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

/* **********************************************************
    Definition: cleanUp

    This function uses two structure reference parameters. It
    clears any content present in the struct member variables.
    This is necessary to be able to perform another search
    without exiting the program.
    ********************************************************** */

void cleanUp(GetFile &clean, TextSearch &search)
{
    clean.fileName.clear();
    clean.textFile.clear();
    search.getText.clear();
    search.timesFound = 0;
    search.searchWord.clear();
    search.searchResult.clear();
}

Example Output:






No comments:

Post a Comment