After receiving some great feedback on my [original program](https://codereview.stackexchange.com/questions/159547/website-spell-checker-in-java), 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: 1. It only accepts English input 2. 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; } }