1
\$\begingroup\$

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:

  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;
    }
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

NB: I didn't read your initial post, so I don't know the content of the feedback you received.

Your program's main should be in a class all its own. When I was in school, Driver was the conventional class name, but App might be a better choice these days. This class will instantiate all the other classes you need.

Comments are not for restating the meaning of code in English. There is more than one way to use comments effectively, but I will refrain from elaborating for brevity's sake. I'm sure there are a lot of articles that you could read on the subject.

Classes should be named as if they can do things, methods should be named after the thing they do. For instance, SuggestSpelling should be a method name instead of a class name.

Avoid class/methods with the same name. You have class SpellChecker and method spellChecker. You should probably rename the latter to check. After all, what does a SpellChecker do? It check. Or checkWord.

Methods should do one thing. However, the "one thing" methods do can be scaled up so that you don't have a bunch of single line methods that are only called sequentially. This is done by choosing a good name (naming things is very important).

Methods generally shouldn't produce output unless they're supposed (you have println all over the place).

I could say more, but it's late. Good luck.

\$\endgroup\$
2
  • \$\begingroup\$ Great advice. Thanks. Especially the bit about the naming conventions and printLn. I'll try to fix this. \$\endgroup\$
    – ary
    Commented Apr 3, 2017 at 3:50
  • \$\begingroup\$ also, I might be wrong about this but isn't SuggestSpelling a constructor and not a method? constructors need to have the same name as the class. \$\endgroup\$
    – ary
    Commented Apr 3, 2017 at 4:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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