I've implemented a program that spell checks a website. Here is the idea that I have in mind:
- Scan all of the words in a web page into a string (using jsoup)
- Filter out all of the HTML markup and code
- Use a spell checking algorithm that reads from a dictionary.txt file and uses probability theory to offer suggestions
I would like to have my code reviewed and would greatly appreciate any input on how to make it more efficient or clean.
There is probably some bad practice followed as I'm new to programming so I apologize in advance if I'm doing something that is obviously wrong.
Some problems I've noticed about my code:
- It only accepts English words
- It will spell check the same word if it's used more than once
- It prints out each suggestion in a new line, so large websites produce a messy output.
Here is the code:
Class 1 (used to call on the methods, basically a neat class to look good)
import java.io.*;
public class BulkSpellChecker extends ParseCleanCheck {
public static void main(String[] args) throws IOException {
System.out.println("Let's get started!");
PageScanner(); // Scan the page and clean it first
SpellChecker(); // Spell check the cleaned page
System.out.println("Thanks for using the spell checker!");
}}
Class 2
import java.io.*;
import java.util.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;
public class ParseCleanCheck {
static Hashtable<String, String> dictionary;// To store all the words of the
// dictionary
static boolean suggestWord;// To indicate whether the word is spelled
// correctly or not.
static Scanner urlInput = new Scanner(System.in);
public static String cleanString = "";
public static String url = "";
public static boolean correct = true;
/**
* PARSER METHOD
*/
public static void PageScanner() throws IOException {
System.out.println("Pick an english website to scan.");
// This do-while loop allows the user to try again after a mistake
do {
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();
cleanString = Jsoup.clean(htmlToClean, Whitelist.none());
correct = false;
} catch (Exception e) {
System.out.println("Incorrect format for a URL. Please try again.");
}
} while (correct);
}
/**
* SPELL CHECKER METHOD
*/
public static void SpellChecker() throws IOException {
dictionary = new Hashtable<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 user_text = "";
// Initializing a spelling suggestion object based on probability
SuggestSpelling suggest = new SuggestSpelling("wordprobabilityDatabase.txt");
// get user input for correction
{
user_text = cleanString;
String[] words = user_text.split(" ");
int error = 0;
for (String word : words) {
suggestWord = true;
String outputWord = checkWord(word);
if (suggestWord) {
System.out.println("Suggestions for " + word + " are: " + suggest.correct(outputWord) + "\n");
error++;
}
}
if (error == 0) {
System.out.println("No mistakes found");
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
/**
* METHOD TO SPELL CHECK THE WORDS IN A STRING. IS USED IN SPELL CHECKER
* METHOD THROUGH THE "WORD" STRING
*/
public static String checkWord(String wordToCheck) {
String wordCheck, unpunctWord;
String word = wordToCheck.toLowerCase();
// if word is found in dictionary then it is spelled correctly, so
// return as it is.
if ((wordCheck = (String) dictionary.get(word)) != null) {
suggestWord = false; // no need to ask for suggestion for a correct
// word.
return wordCheck;
}
// Removing punctuation at end of word and giving it a shot ("." or "."
// or "?!")
int length = word.length();
// Checking for the beginning of quotes(example: "she )
if (length > 1 && word.substring(0, 1).equals("\"")) {
unpunctWord = word.substring(1, length);
if ((wordCheck = (String) dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordCheck;
} else // not found
return unpunctWord; // removing the punctuations and returning
}
// Checking if "." or ",",etc.. at the end is the problem(example: book.
// when book is present in the dictionary).
if (word.substring(length - 1).equals(".")
|| word.substring(length - 1).equals(",")
|| word.substring(length - 1).equals("!")
|| word.substring(length - 1).equals(";")
|| word.substring(length - 1).equals(":")) {
unpunctWord = word.substring(0, length - 1);
if ((wordCheck = (String) dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordCheck;
} 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
&& (word.substring(length - 2).equals(",\"")
|| word.substring(length - 2).equals(".\"")
|| word.substring(length - 2).equals("?\"")
|| word.substring(length - 2).equals("!\""))) {
unpunctWord = word.substring(0, length - 2);
if ((wordCheck = (String) dictionary.get(unpunctWord)) != null) {
suggestWord = false; // no need to ask for suggestion for a
// correct word.
return wordCheck;
} else // not found
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 word;
}}
Class 3
import java.io.*;
import java.util.*;
import java.util.regex.*;
class SuggestSpelling {
private final HashMap<String, Integer> DataBaseWords = new HashMap<String, Integer>();
/**
* Method 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("Uh-Oh Exception occured!");
e.printStackTrace();
}
}
/**
*
* Method that returns an array containing all possible corrections to the
* word passed.
*
*/
private final ArrayList<String> edits(String word) {
ArrayList<String> result = new ArrayList<String>();
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.
}
ArrayList<String> list_edits = edits(word);
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 from the list_edits are found in our word database
// DataBaseWords
// then we return the one verified correction with maximum probability.
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()))
: "Sorry but no possible corrections found!";
}
public static void main(String[] args) throws IOException {
if (args.length > 0) {
System.out.println((new SuggestSpelling("wordprobabilityDatabase.txt")).correct(args[0]));
}
}
}