CS35 Lab 4: Spell Checker

Due by 11:59pm Sunday, October 6, 2014
In this lab, you will implement a C++ linked list. You will then write a program that will load a dictionary into a linked list and perform basic operations on the dictionary. Your program will also have a feature which allows users to use your dictionary to check and correct spelling of documents.

To get started, run update35 from a computer science lab computer. The program update35 will create a cs35/labs/04 directory in your CS home directory, and the program handin35 will subsequently submit files from that directory.

You may choose one partner for this lab. Both partners should be present and working on the code together. You will both be responsible for understanding all concepts, so dividing and conquering is not an option. The academic integrity policy applies to the entire pair; you cannot work or share code with anyone outside of your partner. Also, be sure to indicate who your partner is by including both names at the top of your files and by also selecting the 'p' option when using handin35 for the first time. Only one student in the pair should submit the lab.

You will earn reasonable partial credit for this lab if you complete and test your linked list implementation. So be sure to work in a modular fashion, testing and completing your linked list first before implementing the main program



Implementation details

Here, I list the requirements for each major component of the lab. See the IMPLEMENTATION STRATEGY section below for hints on how to begin attacking the problem.

You have been given the following files (blue indicates you will need to modify/implement in this file):

StringList

I have provided a StringList interface. It is very similar to the interface given in lecture, but adds two additional methods that will be needed for this lab. search takes a string value and returns the index of the first occurence in the list (or -1 if value is not in the list). deleteItem deletes the ith element of the list.

You must define and implement a LinkedStringList class that implements the StringList interface, without altering the StringList interface.

LinkedStringList (and its Requirements)

Begin by thinking about your methods in pseudocode, and then implement them one-by-one. Some requirements to note:

testStringList

You must modify your testStringList.cpp file to make sure your LinkedStringList implementation is working. The ninjas will ask you to show your test file to help you with errors.

Main SpellCheck Program (and its requirements)

Once you have thoroughly tested your LinkedStringList implementation, you should implement the main program. This program has been started for you. To keep the program clean, we divided the main program into three files, similar to what you had for Lab 1. spellCheck.cpp only contains the main loop. Modify this to get it working, but any large implementation details belong in the helper files. Those details should use good top-down design (e.g. one function per feature). Any functions should be declared and defined in spellCheckHelper.h/.cpp respectively. We provided getChoice() for you as an example. To complete the main program:

Take a look at getChoice() to see what options the user has. You should implement each option appropriately in the main while loop. These include: When a user spell-checks a document, you should ask the user for a document, load that document into a List, and then check the spelling of the words one-by-one. When a word does not appear in the dictionary, you should tell the user, then present three options By the end of the spell-check, the original file should now contain the same text, but with the spelling mistakes corrected. A couple pointers when implementing these methods:
An implementation strategy

You should always program incrementally such that you can test your work as you go. Here is one suggested strategy:

  1. Begin by declaring the LinkedStringList class in linkedStringList.h. Remember that you must declare all data members and at least all methods specified in the StringList interface before proceeding.
  2. Start implementing your class in linkedStringList.cpp I suggest stubbing all functions (that is, defining the function and giving a dummy return value). This will let you compile the class properly without having done any actual implementation. An example function stub is:
    /* getItem - returns the value for the ith item in the list
     * @param i, an int for the index of the string to return
     * @return a string containing a scene from the list
     */
    string LinkedStringList::getItem(int i) {
      //TODO: implement this
     
      return "EXAMPLE WORD";
    }
    
  3. Check to see if your class compiles, fix any errors before proceeding. Now, begin implementing one method at a time. I suggest starting with insertAtHead or insertAtTail. Your procedure should be: implement one method, compile, and then test it in testLinkedList.cpp
  4. Implement the destructor last. Carefully consider every possible way that your class might allocate memory on the heap, and be sure that there is a corresponding call to delete for each call to new.
At this point you should have a complete working LinkedStringList class, as well as a very thorough testStringList program.

You should not under any circumstances begin the spell check implementation until you have thoroughly verified the correctness of your LinkedStringList class. Any bugs in your LinkedStringList class will hinder progress on the main program. Begin working on spellCheck.cpp by implementing and testing one feature of the program at a time. Be sure that your solution follows good design/modularity guidelines.


Tips and Hints

Throwing and Handling Exceptions

Your linked list should handle invalid usage by throwing a runtime_error. There is an example in the ArrayStringList implementation from class. For example, if you may want to handle an attempt to get an invalid item:

throw std::runtime_error("Attempt to get out of bounds item");

Here is an example of handling a runtime_error (not required in this lab):

try{
  //do something dangerous
} catch (runtime_error& exc){
  cerr << "Warning: " << exc.what() << endl;
  cerr << "Ignoring illegal behavior." << endl;
}
Don't forget to include the stdexcept library when handling or throwing exceptions.

Handling Upper Case Letters

All of the words in your dictionary will be lower case. It will be nice to be able to spell-check, say, the first word in a sentence without losing the case. One way to do this is to store the word from the document as is, but search for a lower-case version of the word in the dictionary. To do this, you'll need a function that converts a string to lower case. Here is one such implementation:

string lower(string word) {
  string toReturn = "";
  for(int i = 0; i < word.length(); i++){
    toReturn += tolower(word[i]);
  }
  return toReturn;
}

Handling Punctuation

I recommend handling punctuation in the same way. Store each "word" without removing punctuation, but strip this away when checking for the word in the dictionary. For example, the following code removes possible periods from the end of a word.

string stripPunctuation(string word) {
  string toReturn = word;

  if(toReturn[len-1] == '.')) {
    toReturn.erase(len-1);
  }

  return toReturn;
}

Sample Run
The following illustrates how your main program might operate:
$ more q.txt 
The quick broown fox jumps over the lazy dog.
$ ./spellCheck 
Enter dictionary name, or "sowpods" for scrabble dictionary: sowpods

Loading /usr/local/doc/sowpods.txt...
Dictionary Loading Complete
Dictionary contains 267752 words.

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 1

What word do you want to add? oogabooga

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 3

Enter the word you want to check: oogabooga
oogabooga is in the dictionary.

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 2

What word do you want to remove? oogabooga

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 3

Enter the word you want to check: oogabooga
oogabooga is NOT in the dictionary.

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 1

What word do you want to add? bear
Warning: bear is already in the dictionary!

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 4

Enter name of file to spell check: input/q.txt
[broown] is not in the dictionary.
What do you want to do?
  (1) add broown to dictionary.
  (2) ignore word
  (3) correct spelling
3
Enter correction now
brown

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 4

Enter name of file to spell check: input/gettysburg.txt
[battle-field] is not in the dictionary.
What do you want to do?
  (1) add battle-field to dictionary.
  (2) ignore word
  (3) correct spelling
1
[--] is not in the dictionary.
What do you want to do?
  (1) add -- to dictionary.
  (2) ignore word
  (3) correct spelling
2
[--] is not in the dictionary.
What do you want to do?
  (1) add -- to dictionary.
  (2) ignore word
  (3) correct spelling
2
[--] is not in the dictionary.
What do you want to do?
  (1) add -- to dictionary.
  (2) ignore word
  (3) correct spelling
1

(0) Exit
(1) Add word
(2) Remove word
(3) Check word
(4) Spellcheck document

Enter Choice: 0

Goodbye!
$ more input/q.txt
The quick brown fox jumps over the lazy dog. 
Note that the input file q.txt now has no spelling mistakes.
Submit

Once you are satisfied with your program, hand it in by typing handin35 at the unix prompt.

You may run handin35 as many times as you like, and only the most recent submission will be recorded. This is useful if you realize after handing in some programs that you'd like to make a few more changes to them. Only one partner should hand in the code for the lab.