After receiving some great feedback on my original program, I tried to implement everything that was shared and I just want to see if there's anything else that I can change to make my program clean and efficient.
This program:
- Scans all of the words in a web page into a string (using jsoup)
- Filters out all of the HTML markup and code
- Uses a spell checking algorithm that reads from a dictionary.txt file and uses probability theory to offer suggestions
And here are some issues that I know about in my program:
- It only accepts English input
- Sometimes the input will be a punctuation mark or it will be an integer, and the program will print out
"This word is not in our dictionary."
, which can get messy but a String must be returned in that part of the code so I didn't know of a way out of that.
This is the updated code:
public class SpellChecker {
static HashMap<String, String> dictionary;// To store all the words of the
// dictionary
static boolean suggestWord; // To indicate whether the word is spelled
// correctly or not.
public static void main(String[] args) throws IOException {
System.out.println("Let's get started!");
parser.HTMLParser(); // Parse the page and put into a clean string
spellChecker(); // Spell check the cleaned page
System.out.println("Thanks for using the spell checker!");
}
// create a parser object of the SimpleHTMLParser class
static SimpleHTMLParser parser = new SimpleHTMLParser();
Scanner urlInput = new Scanner(System.in);
/**
* SPELL CHECKER METHOD
*/
public static void spellChecker() throws IOException {
dictionary = new HashMap<String, String>();
System.out.println("Searching for spelling errors ... ");
try {
// Read and store the words of the dictionary
BufferedReader dictReader = new BufferedReader(new FileReader("dictionary.txt"));
while (dictReader.ready()) {
String dictInput = dictReader.readLine();
String[] dict = dictInput.split("\\s"); // create an array of
// dictionary words
for (int i = 0; i < dict.length; i++) {
// key and value are identical
dictionary.put(dict[i], dict[i]);
}
}
dictReader.close();
String userText = "";
// creates a suggest object of class SuggestSpelling
SuggestSpelling suggest = new SuggestSpelling("wordprobabilityDatabase.txt");
// get user input for correction
{
userText = parser.getCleanWords();
String[] words = userText.split(" ");
// Remove repetitive words by storing them in a HashSet
Set<String> wordSet = new HashSet<>();
int error = 0;
for (String word : words) {
if (!wordSet.contains(word)) {
removePunct(word);
suggestWord = true;
String outputWord = removePunct(word);
if (suggestWord) {
System.out.println(
"Suggestions for " + word + " are: " + suggest.correct(outputWord) + "\n");
error++;
}
}
// If a word appears more than once, store inside the
// HashSet to avoid re-checking
wordSet.add(word);
}
if (error == 0) {
System.out.println("No mistakes found");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* METHOD TO REMOVE PUNCTUATION
*/
public static String removePunct(String wordToBeChecked) {
String wordInDictionary, unpunctWord;
String wordEntered = wordToBeChecked.toLowerCase();
// if word is found in dictionary then it is spelled correctly, so
// return as it is.
if ((wordInDictionary = dictionary.get(wordEntered)) != null) {
suggestWord = false; // no need to ask for suggestion for a correct
// word.
return wordInDictionary;
}
// Removing punctuation at end of word and giving it a shot ("." or "."
// or "?!")
int length = wordEntered.length();
// Checking for the beginning of quotes(example: "she )
if (length > 1 && wordEntered.substring(0, 1).equals("\"")) {
unpunctWord = wordEntered.substring(1, length);
if ((wordInDictionary = dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordInDictionary;
} else // not found
return unpunctWord; // removing the punctuation and returning
}
// Checking if "." or "," etc. at the end is the problem (example: book.
// when book is present in the dictionary).
if (wordEntered.substring(length - 1).equals(".") || wordEntered.substring(length - 1).equals(",")
|| wordEntered.substring(length - 1).equals("!") || wordEntered.substring(length - 1).equals(";")
|| wordEntered.substring(length - 1).equals(":") || wordEntered.substring(length - 1).equals(" \" ")
|| wordEntered.substring(length - 1).equals("\",") || wordEntered.substring(length - 1).equals("\".")) {
unpunctWord = wordEntered.substring(0, length - 1);
if ((wordInDictionary = dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordInDictionary;
} else {
return unpunctWord; // removing the punctuation and returning it
// clean
}
}
// Checking for (!,\,",etc) ... in the problem (example: watch!" when
// watch is present in the dictionary)
if (length > 2 && (wordEntered.substring(length - 2).equals(",\"")
|| wordEntered.substring(length - 2).equals(".\"") || wordEntered.substring(length - 2).equals("?\"")
|| wordEntered.substring(length - 2).equals("!\"") || wordEntered.substring(length - 2).equals("\""))) {
unpunctWord = wordEntered.substring(0, length - 2);
if ((wordInDictionary = dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordInDictionary;
} else { // not found
suggestWord = false;
return unpunctWord;
} // removing the inflections and returning
}
// If after all of these checks a word could not be corrected, return as
// a misspelled word.
return wordEntered;
}
}
class 2:
class SuggestSpelling {
private final HashMap<String, Integer> DataBaseWords = new HashMap<String, Integer>();
/**
* Constructor that reads the dictionary and checks for probability through
* word occurrences
*/
public SuggestSpelling(String file) throws IOException {
try {
BufferedReader in = new BufferedReader(new FileReader(file));
Pattern p = Pattern.compile("\\w+");
// Reading the dictionary and updating the probabilistic values
// accordingly
for (String temp = ""; temp != null; temp = in.readLine()) {
Matcher m = p.matcher(temp.toLowerCase());
while (m.find()) {
// This will serve as an indicator to probability of a word
DataBaseWords.put((temp = m.group()),
DataBaseWords.containsKey(temp) ? DataBaseWords.get(temp) + 1 : 1);
}
}
in.close();
} catch (IOException e) {
System.out.println("Oh no! An exception occured!");
e.printStackTrace();
}
}
/**
*
* Method that returns an array containing all possible corrections to the
* word passed.
*
*/
private final List<String> edits(String word) {
List<String> result = new ArrayList<>();
for (int i = 0; i < word.length(); ++i) {
result.add(word.substring(0, i) + word.substring(i + 1));
}
for (int i = 0; i < word.length() - 1; ++i) {
result.add(word.substring(0, i) + word.substring(i + 1, i + 2) + word.substring(i, i + 1)
+ word.substring(i + 2));
}
for (int i = 0; i < word.length(); ++i) {
for (char c = 'a'; c <= 'z'; ++c) {
result.add(word.substring(0, i) + String.valueOf(c) + word.substring(i + 1));
}
}
for (int i = 0; i <= word.length(); ++i) {
for (char c = 'a'; c <= 'z'; ++c) {
result.add(word.substring(0, i) + String.valueOf(c) + word.substring(i));
}
}
return result;
}
/**
*
* Method that compares input to dictionary words and returns words that are
* correct while checking for corrections on the others
*
*/
public final String correct(String word) {
if (DataBaseWords.containsKey(word)) {
return word; // this is a perfectly safe word.
}
List<String> list_edits = edits(word);
// put all possible typos into a HashMap to sort them quickly
HashMap<Integer, String> candidates = new HashMap<Integer, String>();
for (String s : list_edits) // Iterating through the list of all
// possible corrections to the word.
{
if (DataBaseWords.containsKey(s)) {
candidates.put(DataBaseWords.get(s), s);
}
}
// In the first stage of error correction, any of the possible
// corrections are found in our word database
// DataBaseWords
// then we return the most probably correction
if (candidates.size() > 0) {
return candidates.get(Collections.max(candidates.keySet()));
}
// In the second stage we apply the first stage method on the possible
// collections of the list_edits.By the second stage statistics
for (String s : list_edits) {
for (String w : edits(s)) {
if (DataBaseWords.containsKey(w)) {
candidates.put(DataBaseWords.get(w), w);
}
}
}
return candidates.size() > 0 ? candidates.get(Collections.max(candidates.keySet()))
: "This word is not in our dictionary.";
}
public static void main(String[] args) throws IOException {
if (args.length > 0) {
System.out.println((new SuggestSpelling("wordprobabilityDatabase.txt")).correct(args[0]));
}
}
}
Class 3:
public class SimpleHTMLParser {
Scanner urlInput = new Scanner(System.in);
String cleanString;
String url = "";
boolean isDone = false;
public void HTMLParser() {
System.out.println("Pick an english website to scan.");
while (!isDone) {
try {
System.out.println("Enter a URL, starting with http://");
url = urlInput.nextLine();
// This creates a document out of the HTML on the web page
Document doc = Jsoup.connect(url).get();
// This converts the document into a string to be cleaned
String htmlToClean = doc.toString();
setCleanWords(Jsoup.clean(htmlToClean, Whitelist.none()));
isDone = true;
} catch (Exception e) {
System.out.println("Incorrect format for a URL. Please try again.");
}
}
}
public void setCleanWords(String cleanString) {
this.cleanString = cleanString;
}
public String getCleanWords() {
return cleanString;
}
}