12
\$\begingroup\$

For my CS2 project, I am supposed to implement a spell-checker. It is supposed to follow the following:

  1. Prompt the user for the name of the file containing the dictionary of correctly spelled words
  2. Read in the name of their dictionary file
  3. Open an input file stream on their filename
  4. If their filename successfully opens:
    1. For each word in the dictionary file:
      • Add the word to the dictionary LinkedSet
    2. Close the dictionary file
  5. Do while the user wants to spell check files: Prompt the user for the name of a file to spell check
    1. Read in the name of their file
    2. Open an input file stream on their file
    3. If the file successfully opens
      1. For each word in their file:
        • Clean the word of extraneous characters
        • Convert the word to lowercase
        • Add the word to the fileBeingSpellChecked LinkedSet
      2. Close the file being spell checked
    4. Create a LinkedSet on the difference of the fileBeingSpellChecked and the dictionary
    5. Display the contents of the difference LinkedSet
    6. Clear the fileBeingSpellChecked LinkedSet
    7. Clear the difference LinkedSet
    8. Prompt the user whether they want to spell check another file
    9. Get their response
  6. Quit

Warning: there is a lot of code below, if reviewers don't want to go through all of the other code, please just focus on my main.cpp file.


SetInterface.h:

#ifndef SET_INTERFACE
#define SET_INTERFACE

#include <vector>

/** @class SetInterface SetInterface.h "SetInterface.h"
 *
 *  Definition of SetInterface class template. 
 */
template <typename T>
class SetInterface 
{
public:

  /** Virtual destructor. */
  virtual ~SetInterface() {}

  /** Gets the current number of entries in this set.
   *  @return The integer number of entries currently in the set. 
   */
  virtual int size() const = 0;

  /** Sees whether this set is empty.
   *
   *  @return True if the set is empty, or false if not. 
   */
  virtual bool isEmpty() const = 0;

  /** Adds a new entry to this set.
   *
   *  @post If successful and unique, newEntry is stored in the set and the
   *        count of items in the set has increased by 1.
   *
   *  @param newEntry The object to be added as a new entry.
   *
   *  @return True if addition was successful and unique, or false if not. 
   */
  virtual bool add(const T&) = 0;

  /** Removes one occurrence of a given entry from this set, if
   *  possible.
   *
   *  @post If successful, anEntry has been removed from the set and
   *        the count of items in the set has decreased by 1.
   *
   *  @param anEntry The value of the entry to be removed.
   *
   *  @return True if removal was successful, or false if not. 
   */
  virtual bool remove(const T&) = 0;

  /** Removes all entries from this set.
   *
   *  @post This set contains no items (thus the count is 0). 
   */
  virtual void clear() = 0;

  /** Counts the number of times a given entry appears in set.
   *
   *  @param anEntry The value of the entry to be counted.
   *
   *  @return The number of times anEntry appears in this set. 
   */
  virtual int count(const T&) const = 0;

  /** Tests whether this set contains a given entry.
   *
   *  @param anEntry The value of the entry to locate.
   *
   *  @return True if this set contains anEntry, or false
   *          otherwise. 
   */
  virtual bool contains(const T&) const = 0;

  /** Converts this set into a vector.
   *
   *  @return A vector containing all the entries in this set. 
   */
  virtual std::vector<T> toVector() const = 0;
};

#endif

Node.h:

#ifndef NODE
#define NODE

template <typename T>
class Node {
 private:
  T item;
  Node<T>* next;

 public:
  Node();
  Node(const T& anItem);
  Node(const T& anItem,
       Node<T>* nextNodePtr);

  void setItem(const T& anItem);
  void setNext(Node<T>* nextNodePtr);

  T getItem() const;
  Node<T>* getNext() const;
};

#include "Node.cpp"

#endif

Node.cpp:

template <typename T>
Node<T>::Node()
  : next(nullptr) {
}

template <typename T>
Node<T>::Node(const T& anItem)
  : item(anItem),
    next(nullptr) {
    }

template <typename T>
Node<T>::Node(const T& anItem,
                     Node<T>* nextNodePtr)
  : item(anItem),
    next(nextNodePtr) {
    }

template <typename T>
void Node<T>::setItem(const T& anItem) {

  item = anItem;
}

template <typename T>
void Node<T>::setNext(Node<T>* nextNodePtr) {

  next = nextNodePtr;
}

template <typename T>
T Node<T>::getItem() const {

  return item;
}

template <typename T>
Node<T>* Node<T>::getNext() const {

  return next;
}

LinkedSet.h:

#ifndef LINKED_SET
#define LINKED_SET

#include "SetInterface.h"
#include "Node.h"

/** @class LinkedBag LinkedBag.h "LinkedBag.h"
 *
 *  Specification of a pointer-based ADT set. */
template <typename T>
class LinkedSet : public SetInterface<T> 
{
private:
  /** Pointer to first node. */
  Node<T>* headPtr;

  /** Number of items in this bag. */
  int itemCount;

  /** Gets a pointer to the node containing the target in this bag.
   *
   * @pre None.
   *
   * @post None.
   *
   * @param target The T value to find.
   *
   * @return A pointer to the node that contains the given target or
   *         nullptr if the bag does not contain the target. 
   */
    Node<T>* getPointerTo(const T& target) const;
public:
    LinkedSet();
    LinkedSet(const LinkedSet<T>& aSet);
    virtual ~LinkedSet();
    Node<T>* getHeadPtr();
    int size() const;
    bool isEmpty() const;
    virtual bool add(const T& newEntry);
    virtual bool remove(const T& anEntry);
    virtual LinkedSet<T> difference(LinkedSet<T>&);
    virtual void clear();
    virtual int count(const T& anEntry) const;
    virtual bool contains(const T& anEntry) const;
    virtual std::vector<T> toVector() const;
};

#include "LinkedSet.cpp"

#endif

LinkedSet.cpp:

template <typename T>
LinkedSet<T>::LinkedSet() : headPtr(nullptr), itemCount(0) {}

template <typename T>
LinkedSet<T>::LinkedSet(const LinkedSet<T>& aBag) 
{
  itemCount = aBag.itemCount;

  if (aBag.headPtr == nullptr) {
    headPtr = nullptr;
  }
  else {
    Node<T>* origChainPtr = aBag.headPtr;

    headPtr = new Node<T>();
    headPtr->setItem(origChainPtr->getItem() );

    Node<T>* newChainPtr = headPtr;

    origChainPtr = origChainPtr->getNext();

    while (origChainPtr != nullptr) {
      T nextItem = origChainPtr->getItem();

      Node<T>* newNodePtr = new Node<T>(nextItem);

      newChainPtr->setNext(newNodePtr);

      newChainPtr = newChainPtr->getNext();

      origChainPtr = origChainPtr->getNext();
    }

    newChainPtr->setNext(nullptr);
  }
}

template <typename T>
LinkedSet<T>::~LinkedSet() 
{
  clear();
}

template <typename T>
Node<T>* LinkedSet<T>::getHeadPtr()
{
  return headPtr;
}

template <typename T>
int LinkedSet<T>::size() const 
{
  return itemCount;
}

template <typename T>
bool LinkedSet<T>::isEmpty() const 
{
  return 0 == itemCount;
}

template <typename T>
bool LinkedSet<T>::add(const T& newEntry) 
{
  if (contains(newEntry)) return false; 
  else
  {
      Node<T>* newNodePtr = new Node<T>();
      newNodePtr->setItem(newEntry);
      newNodePtr->setNext(headPtr);
      headPtr = newNodePtr;

      ++itemCount;
      return true;
  }
}

template <typename T>
bool LinkedSet<T>::remove(const T& anEntry) 
{
  bool canRemoveItem = !isEmpty();

  if (canRemoveItem) {
    Node<T>* entryNodePtr = getPointerTo(anEntry);

    canRemoveItem = entryNodePtr != nullptr;

    if (canRemoveItem) {
      entryNodePtr->setItem(headPtr->getItem()); 
      Node<T>* nodeToDeletePtr = headPtr;
      headPtr = headPtr->getNext();

      nodeToDeletePtr->setNext(nullptr);
      delete nodeToDeletePtr;
      nodeToDeletePtr = nullptr;

      --itemCount;
    }
  }

  return canRemoveItem;
}

template <typename T>
LinkedSet<T> LinkedSet<T>::difference(LinkedSet<T>& linkedSet)
{
    LinkedSet<T> newLinkedSet;
    //Node<T> *ptr1, *ptr2;

    //for(ptr1 = headPtr; ptr1; ptr1 = ptr1->getNext())
    //{
    //for(ptr2 = linkedSet.getHeadPtr(); ptr2; ptr2 = ptr2->getNext())
    //  {
    //      if(ptr1->getItem() == ptr2->getItem()) break;
    //      if(ptr2->getNext() == nullptr) newLinkedSet.add(ptr1->getItem());
    //  }
    //}

    std::vector<T> vec1 = toVector();
    std::vector<T> vec2 = linkedSet.toVector();

    for(int i = 0; i < vec1.size(); ++i)
    {
        for(int j = 0; j < vec2.size(); ++j)
        {
          if(vec1.at(i) == vec2.at(j)) break;
          if(j == vec2.size() - 1) 
        {
          newLinkedSet.add(vec1.at(i));
        }       
    }
    }

    return newLinkedSet;
}

template <typename T>
void LinkedSet<T>::clear() {

  Node<T>* nodeToDeletePtr = headPtr;

  while (headPtr != nullptr) {
    headPtr = headPtr->getNext();

    nodeToDeletePtr->setNext(nullptr);
    delete nodeToDeletePtr;

    nodeToDeletePtr = headPtr;
  }
  // headPtr is nullptr; nodeToDeletePtr is nullptr.

  itemCount = 0;
}

template <typename T>
bool LinkedSet<T>::contains(const T& anEntry) const 
{
  return getPointerTo(anEntry) != nullptr;
}

template <typename T>
int LinkedSet<T>::count(const T& anEntry) const 
{
  int frequency = 0;

  Node<T>* curPtr = headPtr;

  while (curPtr != nullptr) {
    if (curPtr->getItem() == anEntry) {
      ++frequency;
    }

    curPtr = curPtr->getNext();
  }

  return frequency;
}

template <typename T>
std::vector<T> LinkedSet<T>::toVector() const {

  std::vector<T> bagContents;

  Node<T>* curPtr = headPtr;

  while (curPtr != nullptr) {
    bagContents.push_back(curPtr->getItem() );

    curPtr = curPtr->getNext();
  }

  return bagContents;
}

template <typename T>
Node<T>* LinkedSet<T>::getPointerTo(const T& target) const {

  bool found = false;

  Node<T>* curPtr = headPtr;

  while (!found && curPtr != nullptr) {
    if (curPtr->getItem() == target) {
      found = true;
    }
    else {
      curPtr = curPtr->getNext();
    }
  }

  return curPtr;
}

main.cpp:

#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include "LinkedSet.h"

char getSanitizedChar()
{
  // absorb newline character (if existant) from previous input
  if('\n' == std::cin.peek()) std::cin.ignore();
  return std::tolower(std::cin.get());
}

std::string cleanString(std::string str)
{
    std::string remove = "!@#$%^&*()_-+={}[]:;\"\'`<>,.?/|\\"; 
    for (size_t i = 0; i < remove.length(); ++i)
    {
        str.erase(std::remove(str.begin(), str.end(), remove.at(i)), str.end());
    }
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    return str;
}

template <typename T>
void displaySet(LinkedSet<T> set)
{
    std::vector<T> vec = set.toVector();
    std::cout << vec.size() << std::endl;
    for (int i = 0; i < vec.size(); ++i)
    {
        std::cout << vec.at(i) << " ";
    }
    std::cout << std::endl;
}

int main() 
{    
    LinkedSet<std::string> dictionary;
    LinkedSet<std::string> fileBeingChecked;
    std::string defaultDict = "../small.dat";  //"/usr/share/dict/american-english";
    std::string dictFilename;
    std::string line;

    std::cout << "Enter name of dictionary file (press <ENTER> for default): ";
    std::getline(std::cin, dictFilename);
    std::ifstream dict(dictFilename.length() ? dictFilename : defaultDict);
    if(dict.good())
    {
        std::cout << "Loading file contents..." << std::endl;
        while(std::getline(dict, line))
        {
            std::string word;
            std::istringstream lineStream(line);
            while(lineStream >> word)
            {
                dictionary.add(word);
            }
        }
    }
    else
    {
        std::cout << "Error opening dictionary file" << std::endl;
        return -1;
    }
    dict.close();

    std::string checkFilename;
    std::string defaultCheck = "../small.txt";
    do
    {
        std::cout << "Enter the name of a file to spell check (press <ENTER> for default): ";
        std::getline(std::cin, checkFilename);
        std::ifstream check(checkFilename.length() ? checkFilename : defaultCheck);
        if (check.good())
        {
            while(std::getline(check, line))
            {
                std::string word;
                std::istringstream lineStream(line);
                while(lineStream >> word)
                {
                    word = cleanString(word);
                    fileBeingChecked.add(word);
                }
            }
            std::cout << fileBeingChecked.size() << std::endl;
        }
        else
        {
            std::cout << "Error opening file to check." << std::endl;
        }
        check.close();

        LinkedSet<std::string> diff(fileBeingChecked.difference(dictionary));
        displaySet(diff);
        fileBeingChecked.clear();

        std::cout << "Check another file (y/N)? ";
    } while('y' == getSanitizedChar());
}
\$\endgroup\$
3
\$\begingroup\$

(if existant)

Spellin errah!

  • void displaySet(LinkedSet<T> set) wants to be

    std::ostream& operator<<(std::ostream&, const LinkedSet<T>&);
    

    Along the same line I would argue that

        while(lineStream >> word)
        {
            dictionary.add(word);
        }
    

    is

    std::istream operator>>(std::istream, LinkedSet<T>&)
    

    in disguise.

  • difference is suboptimal. If it is OK to convert LinkedSets to vectors, it is surely OK to sort the vectors.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.