Build a Smart Autocorrect Engine

Build a Python CLI autocorrect engine using Levenshtein distance and word frequency.

Introduction

30 Second Summary

Every time you type on your phone and it fixes "teh" to "the", that's autocorrect at work. Behind the scenes, an algorithm measures how "close" a misspelled word is to every real word, then picks the most likely correction using word frequency data.

In this project, you will build a command-line autocorrect engine in Python that corrects misspelled words using the Levenshtein edit distance algorithm and word frequency ranking.

What You'll Build

You type a messy sentence full of typos, press Enter, and watch your tool instantly return the corrected version with a confidence score for each fix.

By the end of this project, you'll have:

  • A working edit distance algorithm built from scratch using dynamic programming that measures how many character changes separate two words.
  • A probabilistic ranking system that combines edit distance with word frequency data so your engine knows "teh" should become "the" (common) not "tee" (rare).
  • An interactive CLI tool that corrects full sentences and shows ranked suggestions with the algorithm's reasoning for each fix.
  • Secret Mission: add keyboard-distance weighting so adjacent-key typos like "thw" rank "the" higher than random substitutions.

Are there any prerequisites?

You should be comfortable with Python basics: functions, loops, dictionaries, and sets. No prior knowledge of NLP or algorithms is required.

Before We Start

Before We Start...

Before we dive in, let's lock in what you're about to build and why it matters.

You're building a CLI autocorrect engine that uses Levenshtein edit distance and word frequency ranking to correct misspelled text. This combines dynamic programming with probabilistic language models, the same core algorithm behind every phone keyboard and search engine spell-checker.

Set Up Your Project Environment

Every autocorrect system needs two things: an algorithm to measure how "close" a typo is to a real word, and frequency data to rank which corrections are most likely.

In this step, you will create your project folder, install a library called wordfreq that provides word frequency data, and write a script that loads a 50,000-word English vocabulary.

In this step, get ready to:
  • Create a project folder with a virtual environment.
  • Install the wordfreq library for word frequency data.
  • Create autocorrect.py and verify the library works.
Create your project folder and virtual environment

A virtual environment keeps your project's libraries isolated from the rest of your system.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or Command Prompt (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir autocorrect-engine
cd autocorrect-engine
  • Create a virtual environment by running:
python -m venv venv
  • Confirm the virtual environment was created by running:
ls

You should see a venv folder listed in the output.

  • Activate the virtual environment:

macOS

source venv/bin/activate

Windows

venv\Scripts\activate

Your terminal prompt now shows (venv) at the beginning, confirming the virtual environment is active.

Don't see (venv) in your prompt?

On Windows, if you see a permissions error, open PowerShell as Administrator and run Set-ExecutionPolicy RemoteSigned then try activating again.

On macOS, make sure you typed source before the path. Without it, the shell tries to execute the script directly and fails silently.

help me activate my Python virtual environment

  • Install the wordfreq library by running:
pip install wordfreq

You should see download progress and a line that says Successfully installed followed by the package names.

Seeing an installation error?

Make sure (venv) is showing in your prompt. If not, the virtual environment is not active and pip might fail or install globally.

If you see a network error, check your internet connection and try again.

help me install wordfreq with pip

Create autocorrect.py and verify wordfreq works

Now you will write a short script that loads word frequency data into a vocabulary set. This vocabulary is the dictionary your autocorrect engine will search through.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • In VS Code, click File in the top menu bar.
  • Click Open Folder.
  • Select the autocorrect-engine folder on your Desktop, then click Open.
  • In the Explorer sidebar on the left, click the new file icon (a page with a plus sign).
  • Type autocorrect.py as the filename and press Enter.
  • Paste the following code into autocorrect.py:
from wordfreq import zipf_frequency, top_n_list


# --- Vocabulary ---

VOCABULARY = set(top_n_list('en', 50000))

print(zipf_frequency('the', 'en'))
print(len(VOCABULARY))

What does this code do?

  • zipf_frequency returns a word's frequency on the Zipf scale (higher number = more common). The word "the" scores around 7.73, making it one of the most common English words.
  • top_n_list('en', 50000) loads the 50,000 most common English words from wordfreq's built-in dataset.
  • VOCABULARY stores those words in a set for fast lookups. This is the dictionary your autocorrect will search through to find corrections.
  • Save autocorrect.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).

Before you run this, what do you think the two print statements will output?

  • Switch back to your terminal (make sure you are still in the autocorrect-engine folder with (venv) active) and run:
python autocorrect.py

You should see two lines of output:

  • 7.73 (the Zipf frequency of "the" in English).
  • 50000 (the number of words loaded into your vocabulary).

Seeing a ModuleNotFoundError?

This means wordfreq is not installed in the active environment. Confirm your prompt shows (venv). If it does not, activate the virtual environment again, then re-run pip install wordfreq.

help me fix a ModuleNotFoundError for wordfreq

✔️ Awesome, I've got everything!

Great. Make sure you have saved autocorrect.py before moving on.

ⓧ I'd like to double check the full code

Here is the complete autocorrect.py file so far:

from wordfreq import zipf_frequency, top_n_list


# --- Vocabulary ---

VOCABULARY = set(top_n_list('en', 50000))

print(zipf_frequency('the', 'en'))
print(len(VOCABULARY))

Your environment is ready and loaded with 50,000 English words ranked by frequency. Next up, you will build the edit distance algorithm that measures how far a misspelled word is from each vocabulary word.

Build the Edit Distance Algorithm

Your project environment is ready with a 50,000-word vocabulary loaded from wordfreq. Now you need a way to measure how "close" a misspelled word is to a correctly spelled word.

Edit distance (specifically Levenshtein distance) counts the minimum number of single-character operations needed to transform one string into another. It is the core algorithm behind every spell-checker and autocorrect system.

In this step, get ready to:
  • Implement the Levenshtein edit distance algorithm using dynamic programming.
  • Build a naive correction function that finds the closest vocabulary word by distance alone.
  • Observe why edit distance alone produces poor suggestions.
Implement the Levenshtein distance function

The Levenshtein algorithm uses dynamic programming to fill a matrix where each cell represents the cost of transforming a substring of the source into a substring of the target. Three operations are available at each step: insertion, deletion, and substitution.

  • In autocorrect.py, delete the two print lines at the bottom of your file (the print(zipf_frequency('the', 'en')) and print(len(VOCABULARY)) lines).
  • Add a # --- Edit Distance --- section comment below the VOCABULARY line, leaving a blank line above it.
  • Paste the following edit_distance function below that comment:
def edit_distance(source, target):
    """Compute the Levenshtein edit distance between two strings using dynamic programming."""
    m = len(source)
    n = len(target)

    # Create (m+1) x (n+1) matrix
    matrix = [[0] * (n + 1) for _ in range(m + 1)]

    # Initialize first column (deletions from source)
    for i in range(m + 1):
        matrix[i][0] = i

    # Initialize first row (insertions into source)
    for j in range(n + 1):
        matrix[0][j] = j

    # Fill the matrix
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            deletion = matrix[i - 1][j] + 1
            insertion = matrix[i][j - 1] + 1

            if source[i - 1] == target[j - 1]:
                substitution = matrix[i - 1][j - 1]
            else:
                substitution = matrix[i - 1][j - 1] + 1

            matrix[i][j] = min(deletion, insertion, substitution)

    return matrix[m][n]

What does this code do?

The function builds a matrix of size (m+1) x (n+1) where m and n are the lengths of the source and target strings.

  • The first row and column represent transforming from/to an empty string (each step costs 1).
  • Each remaining cell takes the minimum of three options: delete a character (+1), insert a character (+1), or substitute (0 if characters match, +1 if they differ).
  • The bottom-right cell holds the final answer: the minimum total operations needed.
  • Now add a test block at the bottom of the file to run the function:
if __name__ == '__main__':
    print(edit_distance('kitten', 'sitting'))
    print(edit_distance('teh', 'the'))

What does this test do?

The if __name__ == '__main__' guard ensures this code only runs when you execute the file directly. It tests two classic examples: "kitten" to "sitting" (3 edits) and "teh" to "the" (2 edits, because a character swap requires two substitutions in Levenshtein distance).

  • Save autocorrect.py.
  • Run your script by running this command:
python autocorrect.py

You should see two numbers printed: 3 (kitten to sitting) and 2 (teh to the).

Seeing a different number or an error?

  • Make sure you saved the file before running it.
  • Check that matrix[i][j] uses min(deletion, insertion, substitution) with all three variables spelled exactly as defined above.
  • Confirm your if __name__ == '__main__': line has no indentation (it sits at the top level of the file).

help me debug my edit_distance function

Add a naive correction function

Now that you can measure distance between any two words, you can build a spell-checker. The simplest approach is to compare the misspelled word against every word in your vocabulary and pick the one with the smallest edit distance.

  • In autocorrect.py, add this function between your edit_distance function and the if __name__ block:
def naive_correct(word, vocabulary):
    best_word = None
    best_dist = float('inf')
    for vocab_word in vocabulary:
        dist = edit_distance(word, vocab_word)
        if dist < best_dist:
            best_dist = dist
            best_word = vocab_word
    return best_word, best_dist

What does this code do?

  • It iterates through all 50,000 words in the vocabulary and computes the edit distance to the misspelled word.
  • It keeps track of the word with the smallest distance found so far.
  • It returns the closest word and its distance. This might take 1-2 seconds per word since it compares against the entire vocabulary.

Now update the if __name__ == '__main__': block to test the naive correction.

  • In autocorrect.py, find this line inside your if __name__ block:
    print(edit_distance('teh', 'the'))
  • Add the following lines below it, inside the same if __name__ block:
    for w in ['teh', 'speling', 'correc']:
        result, dist = naive_correct(w, VOCABULARY)
        print(f'{w} -> {result} (distance: {dist})')
  • Save autocorrect.py.

Before you run this, what do you think "teh" will be corrected to? Most people expect "the" since it is the most common word in English and looks like an obvious typo.

  • Run your script:
python autocorrect.py

You will see 3 and 2 from the edit distance tests, followed by the naive corrections. Notice the problem: "teh" is NOT corrected to "the".

Instead, you will see a word like "ten" or "tee" suggested. That is because "teh" is only distance 1 from words like "ten" (swap the last letter), but distance 2 from "the" (a swap of adjacent characters costs two substitutions in Levenshtein distance).

Why does naive correction fail here?

The naive approach picks whichever word has the smallest edit distance. It has no concept of word frequency or probability. "Ten" and "tee" are both distance 1 from "teh", while "the" is distance 2 away.

A human knows that "the" is overwhelmingly the most likely intended word. The algorithm does not. This is the gap that frequency-based ranking will fix in the next step.

Script taking a long time?

  • The naive function checks all 50,000 vocabulary words for each misspelled word. It may take a few seconds per correction. This is expected for pure Python.
  • If it takes more than 30 seconds total, make sure you are not accidentally running it outside your virtual environment (which might use a slower system Python).

help me debug my naive correction function

✔️ Awesome, I've got everything!

Great. Double check you have saved autocorrect.py and that running it prints the edit distances plus the naive corrections.

ⓧ I'd like to double check the full code

Your autocorrect.py should contain the following sections in order. Scroll up and confirm each is present:

  • The from wordfreq import ... line and VOCABULARY set (from Step 1).
  • The # --- Edit Distance --- section comment.
  • The edit_distance(source, target) function with the full dynamic programming matrix logic.
  • The naive_correct(word, vocabulary) function that iterates the vocabulary.
  • The if __name__ == '__main__': block with two edit_distance prints and a for loop testing naive_correct on three misspelled words.

You have built the Levenshtein distance algorithm from scratch and proven that distance alone is not enough for good spell-correction. Next up, you will add word frequency data to break ties and make your corrector actually suggest "the" for "teh".

Add Frequency-Based Ranking

In Step 2, you saw the naive corrector suggest random words for common misspellings. "teh" might have returned "tee" or "ten" instead of "the" because the algorithm only measured distance, not how common a word is.

Real spell-checkers fix this by combining edit distance with word frequency. A word like "the" appears billions of times in English text, so even when it ties on distance with a rare word, it should always win. In this step, you will build that probability-aware ranking system.

In this step, get ready to:
  • Build a scoring function that combines edit distance with word frequency.
  • Build a smart correction function using candidate generation.
  • Add sentence correction that fixes every word in a string.
Build a scoring function that combines edit distance with word frequency

The key insight is that word frequency breaks ties. "teh" is edit distance 1 from both "the" and "tee". But "the" has a zipf_frequency of 7.73 while "tee" scores much lower. A scoring function that penalizes distance but rewards frequency will always prefer "the".

  • In autocorrect.py, find the naive_correct function and the if __name__ == '__main__' block at the bottom.
  • Delete both of them entirely. They served their purpose in Step 2, and you are replacing them with a smarter approach.
  • In their place, add the following scoring section:
# --- Scoring ---

PENALTY_WEIGHT = 2.0


def score_candidate(candidate_word, distance):
    """Score a candidate correction using word frequency and edit distance."""
    frequency = zipf_frequency(candidate_word, 'en')
    score = frequency - (distance * PENALTY_WEIGHT)
    return score

What does this code do?

The scoring formula is simple but powerful. It starts with a word's zipf_frequency (how common it is on a scale of 0 to 8) and subtracts a penalty for each edit needed.

With PENALTY_WEIGHT = 2.0, a word that requires 1 edit loses 2 points from its frequency score. So "the" (frequency 7.73) at distance 1 scores 5.73, while a rare word at the same distance might score below zero.

  • Add a temporary test block at the bottom of the file to verify your scoring function works:
if __name__ == '__main__':
    # Compare scores for two words at the same distance
    print(f"the (distance 1): {score_candidate('the', 1):.2f}")
    print(f"tee (distance 1): {score_candidate('tee', 1):.2f}")
  • Save autocorrect.py and run it:
python autocorrect.py

You should see "the" scoring around 5.73 while "tee" scores much lower. Frequency makes all the difference.

Seeing an error?

If you see a NameError for score_candidate, make sure you deleted naive_correct and added the scoring section after the edit_distance function, not inside it.

If you see a NameError for zipf_frequency, check that your import line at the top still reads from wordfreq import zipf_frequency, top_n_list.

help me fix my score_candidate function

Build the smart correction function using candidate generation

The scoring function needs candidates to score. Instead of checking every word in the vocabulary (like naive_correct did), you will filter down to words within a maximum edit distance first. This is called candidate generation.

  • In autocorrect.py, add the candidate generation section between the edit_distance function and the # --- Scoring --- section:
# --- Candidate Generation ---

def generate_candidates(word, vocabulary, max_distance=2):
    """Find all vocabulary words within max_distance edits of the given word."""
    candidates = []
    for vocab_word in vocabulary:
        # Skip words that differ too much in length (optimization)
        if abs(len(vocab_word) - len(word)) > max_distance:
            continue
        distance = edit_distance(word, vocab_word)
        if distance <= max_distance:
            candidates.append((vocab_word, distance))
    return candidates

What does this code do?

The generate_candidates function loops through the vocabulary and keeps every word within max_distance edits. The length check is an optimization. A 3-letter word can never be within 2 edits of a 9-letter word, so it skips those comparisons entirely.

  • Now add the correction function below the # --- Scoring --- section. Add a new section header # --- Correction --- and paste this code:
# --- Correction ---

def correct(word, vocabulary):
    """Return the best correction candidates for a misspelled word, ranked by score."""
    word_lower = word.lower()

    # If the word is already known, return it
    if word_lower in vocabulary:
        return [(word_lower, 0, zipf_frequency(word_lower, 'en'))]

    candidates = generate_candidates(word_lower, vocabulary)

    if not candidates:
        return [(word_lower, 0, 0.0)]

    scored = []
    for candidate_word, distance in candidates:
        score = score_candidate(candidate_word, distance)
        scored.append((candidate_word, distance, score))

    # Sort by score descending
    scored.sort(key=lambda x: x[2], reverse=True)
    return scored[:5]

What does this code do?

The correct function ties everything together. It first checks if the word is already correct (in the vocabulary). If not, it generates candidates, scores each one, sorts by score descending, and returns the top 5.

The result is a list of tuples: (candidate_word, distance, score). The highest-scoring candidate comes first.

  • Replace your if __name__ test block with this updated version that tests the full correction pipeline:
if __name__ == '__main__':
    for w in ['teh', 'speling', 'correc']:
        results = correct(w, VOCABULARY)
        print(f'\nCorrections for "{w}":')
        for candidate, distance, score in results:
            print(f'  {candidate} (distance: {distance}, score: {score:.2f})')

Before you run this, think about it: what do you expect the top candidate for "teh" to be now? Will it still suggest the same word as the naive corrector from Step 2?

  • Save autocorrect.py and run it:
python autocorrect.py

You should see "teh" now correctly suggests "the" as the top candidate with a high combined score. The frequency ranking solved the problem you saw in Step 2.

Why is this better than the naive approach?

The naive corrector from Step 2 returned whichever word happened to be closest by edit distance alone. With 50,000 vocabulary words, many tied at the same distance, and the winner was essentially random.

Now, frequency breaks those ties decisively. "the" (frequency 7.73) crushes "tee" because it appears billions of times more often in English text. This is the same principle behind every phone keyboard and search engine spell-checker.

Still seeing unexpected top candidates?

Make sure PENALTY_WEIGHT is set to 2.0. A weight that is too low lets distance-2 words compete with distance-1 words.

If the script takes more than a few seconds per word, check that the length filter in generate_candidates is working. The line if abs(len(vocab_word) - len(word)) > max_distance should skip words that differ too much in length.

help me debug my autocorrect scoring and candidate generation

Add sentence correction

Correcting single words is useful, but real autocorrect handles full sentences. You need a function that splits text into words, corrects each misspelled one, and preserves punctuation.

  • In autocorrect.py, add the correct_sentence function below the correct function, still inside the # --- Correction --- section:
def correct_sentence(text, vocabulary):
    """Correct all misspelled words in a sentence."""
    words = text.split()
    corrections = []

    for original_word in words:
        # Preserve punctuation
        prefix = ""
        suffix = ""
        clean_word = original_word

        while clean_word and not clean_word[0].isalpha():
            prefix += clean_word[0]
            clean_word = clean_word[1:]
        while clean_word and not clean_word[-1].isalpha():
            suffix = clean_word[-1] + suffix
            clean_word = clean_word[:-1]

        if not clean_word:
            corrections.append((original_word, original_word, 0, 0.0))
            continue

        results = correct(clean_word, vocabulary)
        best_word, distance, score = results[0]

        corrected = prefix + best_word + suffix
        corrections.append((original_word, corrected, distance, score))

    return corrections

What does this code do?

The function strips punctuation from each word before correcting it, then reattaches it afterward. This means input like "hello," won't confuse the spell-checker by looking for "hello," in the vocabulary.

It returns a list of tuples: (original_word, corrected_word, distance, score). This gives you everything needed to show the learner what changed and why.

  • Replace your if __name__ test block one more time to test sentence correction:
if __name__ == '__main__':
    # Test sentence correction
    corrections = correct_sentence('tha quik brwn fox', VOCABULARY)
    corrected_words = [c[1] for c in corrections]
    print(' '.join(corrected_words))
    for orig, corr, dist, sc in corrections:
        if orig.lower() != corr.lower():
            print(f'  "{orig}" -> "{corr}" (distance: {dist}, score: {sc:.2f})')
  • Save autocorrect.py and run it:
python autocorrect.py

You should see the corrected sentence printed with each changed word showing its original form, the correction, and its score.

Some words not getting corrected?

If a word stays unchanged, it might already be in the vocabulary (correctly spelled but uncommon) or it might be more than 2 edits away from any vocabulary word.

Check that max_distance=2 in generate_candidates is giving enough range. Words with 3+ errors won't be caught.

help me debug my correct_sentence function

✔️ Awesome, I've got everything!

Great. Double check you have saved autocorrect.py and that running it produces correct suggestions for "teh" and corrected sentences.

ⓧ I'd like to double check the full code

Your autocorrect.py should contain these sections in order (scroll up to confirm each is present). Your temporary if __name__ test block at the bottom is fine to keep for now.

  • Imports: from wordfreq import zipf_frequency, top_n_list.
  • Vocabulary: VOCABULARY = set(top_n_list('en', 50000)).
  • Edit distance: the edit_distance(source, target) function with the full dynamic programming matrix.
  • Candidate generation: generate_candidates(word, vocabulary, max_distance=2) with the length filter optimization.
  • Scoring: PENALTY_WEIGHT = 2.0 and score_candidate(candidate_word, distance) using zipf_frequency.
  • Correction: correct(word, vocabulary) returning top 5 scored candidates, and correct_sentence(text, vocabulary) preserving punctuation.

Your autocorrect engine now makes intelligent corrections powered by real-world word frequency data. Next up, you will wrap this into an interactive CLI tool so you can demo it live and see the algorithm's reasoning in real time.

Build the Interactive CLI

Your autocorrect engine now picks the right word using both edit distance and frequency data.

A demo-able tool you can show in an interview is worth more than a script that just runs once. In this step, you will wrap your algorithm in an interactive CLI that lets you test corrections in real-time and see the algorithm's reasoning for each suggestion.

In this step, get ready to:
  • Build formatted output that shows ranked correction candidates with their scores.
  • Add sentence-mode display with a per-word correction breakdown.
  • Create an interactive loop that accepts text input and routes to the correct display mode.
Build an interactive input loop

When a user types a single misspelled word, your CLI should display the top 5 correction candidates in a clean table showing edit distance, word frequency, and the combined score.

  • In autocorrect.py, scroll to the bottom of the file (below the correct_sentence function).
  • Add the following display_word_corrections function by copying this code:
# --- Interactive CLI ---

def display_word_corrections(word, vocabulary):
    """Display detailed correction candidates for a single word."""
    results = correct(word, vocabulary)
    print(f'\n  Corrections for "{word}":')
    print(f"  {'Candidate':<15} {'Distance':<10} {'Frequency':<12} {'Score':<8}")
    print(f"  {'-'*45}")
    for candidate_word, distance, score in results:
        freq = zipf_frequency(candidate_word, 'en')
        print(f"  {candidate_word:<15} {distance:<10} {freq:<12.2f} {score:<8.2f}")

What does this code do?

This function takes a misspelled word, runs it through your correct() function from Step 3, and prints the top 5 candidates in a formatted table.

  • The f-string formatting (:<15, :<10) creates fixed-width columns so the output lines up neatly.
  • For each candidate, it looks up the raw frequency separately with zipf_frequency so the user can see both the frequency and the final combined score.
  • Save autocorrect.py.
  • Test the new function by running this command in your terminal:
python -c "from autocorrect import display_word_corrections, VOCABULARY; display_word_corrections('teh', VOCABULARY)"

You should see a table with candidates like "the", "ten", "tea" ranked by score, with "the" at the top thanks to its high frequency.

Seeing a NameError?

Make sure the function is placed AFTER the correct_sentence function in your file.

Check that the # --- Interactive CLI --- comment appears on its own line above the function definition.

help me debug a NameError in my autocorrect display function

Add formatted output showing the algorithm's reasoning

For sentence input, users need to see the original text, the corrected version, and a breakdown explaining each correction the algorithm made.

  • Below your display_word_corrections function, add the display_sentence_correction function by copying this code:
def display_sentence_correction(text, vocabulary):
    """Display sentence correction with a breakdown of changes."""
    corrections = correct_sentence(text, vocabulary)

    corrected_words = [c[1] for c in corrections]
    corrected_sentence = " ".join(corrected_words)

    print(f"\n  Original:  {text}")
    print(f"  Corrected: {corrected_sentence}")

    changes = [(orig, corr, dist, sc) for orig, corr, dist, sc in corrections if orig.lower() != corr.lower()]
    if changes:
        print(f"\n  Changes ({len(changes)} corrections):")
        for original, corrected, distance, score in changes:
            freq = zipf_frequency(corrected.strip(".,!?;:"), 'en')
            print(f'    "{original}" -> "{corrected}" (distance: {distance}, frequency: {freq:.2f}, score: {score:.2f})')
    else:
        print("\n  No corrections needed!")

What does this code do?

  • It runs correct_sentence() to get all corrections, then assembles the corrected sentence from the results.
  • It prints the original and corrected sentences side-by-side so the user can compare them visually.
  • The changes list filters to only words that actually changed, then prints each one with its distance, frequency, and combined score.
  • The .strip(".,!?;:") removes punctuation before looking up frequency, so a trailing period doesn't break the lookup.
  • Save autocorrect.py.
  • Test the sentence display by running this command:
python -c "from autocorrect import display_sentence_correction, VOCABULARY; display_sentence_correction('tha quik brwn fox', VOCABULARY)"

You should see the original sentence, the corrected version, and a change breakdown showing each misspelled word mapped to its correction with distance and frequency details.

Seeing unexpected corrections?

If some words correct to unexpected results, check that your PENALTY_WEIGHT is set to 2.0 in your file.

Make sure the list comprehension filtering uses orig.lower() != corr.lower() to properly detect changes.

help me debug my sentence correction output

Add sentence-mode display

Both display functions work individually. Now you need a main() loop that accepts user input, detects whether it is a single word or a sentence, and routes to the correct display function.

  • Below your display_sentence_correction function, add the main() function and the script guard by copying this code:
def main():
    """Run the interactive autocorrect CLI."""
    print("=" * 50)
    print("  Smart Autocorrect Engine")
    print("=" * 50)
    print("  Type a word to see correction candidates.")
    print("  Type a sentence to see it corrected.")
    print('  Type "quit" to exit.')
    print("=" * 50)

    while True:
        try:
            user_input = input("\n> ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nGoodbye!")
            break

        if not user_input:
            continue

        if user_input.lower() == "quit":
            print("Goodbye!")
            break

        # Single word vs sentence
        if " " not in user_input:
            display_word_corrections(user_input, VOCABULARY)
        else:
            display_sentence_correction(user_input, VOCABULARY)


if __name__ == "__main__":
    main()

What does this code do?

  • The banner prints a welcome message with usage instructions when the script starts.
  • The while True loop keeps prompting for input until the user types "quit" or presses Ctrl+C.
  • The routing logic is simple: if the input has no spaces, treat it as a single word and show candidates. If it has spaces, treat it as a sentence and show the full correction.
  • The if __name__ == "__main__" guard ensures main() only runs when you execute the file directly, not when you import it.
  • Save autocorrect.py.

Before you run this, what do you think the output will look like when you type "tha quik brwn fox"? How many words do you expect the algorithm to correct?

  • Run your autocorrect engine by executing:
python autocorrect.py
  • You should see the banner with usage instructions and a > prompt waiting for your input.
  • Type teh and press Enter to see single-word mode with ranked candidates.
  • Type tha quik brwn fox and press Enter to see the corrected sentence with a per-word breakdown.
  • Type quit to exit the tool.

You should see the original sentence on one line, the corrected sentence on the next, and a changes section showing each correction with its distance, frequency, and score.

CLI hangs or doesn't respond?

The first correction may take 1-3 seconds because it is computing edit distance against 50,000 vocabulary words. This is normal for pure Python.

If the script never shows the banner, check that if __name__ == "__main__": main() is at the very bottom of your file with no indentation.

help me debug my autocorrect CLI not starting

✔️ Awesome, I've got everything!

Great. Double check you have saved autocorrect.py and the CLI is working for both single words and sentences.

ⓧ I'd like to double check the full code

Your autocorrect.py file is now quite long. Scroll through it and confirm these sections appear in order:

  • Imports (from wordfreq import zipf_frequency, top_n_list).
  • Vocabulary (VOCABULARY = set(top_n_list('en', 50000))).
  • edit_distance(source, target) function.
  • generate_candidates(word, vocabulary, max_distance=2) function.
  • PENALTY_WEIGHT = 2.0 and score_candidate(candidate_word, distance) function.
  • correct(word, vocabulary) and correct_sentence(text, vocabulary) functions.
  • display_word_corrections(word, vocabulary) function.
  • display_sentence_correction(text, vocabulary) function.
  • main() function with the interactive loop.
  • if __name__ == "__main__": main() at the very bottom.

You now have a fully interactive autocorrect engine that corrects misspelled text and explains its reasoning. Next up, you will tackle the Secret Mission and make the algorithm even smarter by teaching it about keyboard layout.

Secret mission

Add Keyboard-Distance Weighting

Real autocorrect systems know that "thw" is more likely a typo of "the" than "thx" because W and E are adjacent on a QWERTY keyboard. Can you make your engine just as smart?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. The wordfreq library is open-source and free. Decide whether to keep your project files or delete them.

Resources you used:

  • The autocorrect-engine project folder on your Desktop (contains autocorrect.py, the virtual environment, and installed packages).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your autocorrect engine or want to extend it further.

  • Your autocorrect-engine folder stays on your Desktop, ready for you to reactivate the virtual environment and run python autocorrect.py anytime.

Pause - I'll come back to this later

Shut down any running processes to free up memory. Your files stay on disk for when you return.

  • If the autocorrect CLI is still running in your terminal, press Ctrl+C or type quit to exit.
  • Deactivate the virtual environment by running:

Delete - I don't want to use this again

Remove all project files and start fresh. This deletes your code, the virtual environment, and all installed packages.

  • If the autocorrect CLI is still running, press Ctrl+C or type quit to exit.
  • Deactivate the virtual environment by running:
deactivate
  • Navigate to your Desktop and delete the project folder by running:

macOS

cd ~/Desktop
rm -rf autocorrect-engine

Windows

cd ~\Desktop
rmdir /s /q autocorrect-engine
  • Confirm the folder is gone by running ls (macOS) or dir (Windows) on your Desktop. You should no longer see autocorrect-engine in the output.

Nice Work!

Nice Work!

You just built a fully functional autocorrect engine from scratch. This is the same probabilistic algorithm that powers every phone keyboard and search engine spell-checker, and you can demo it live in your terminal.

You've learned how to:

  • Build a Levenshtein edit distance algorithm from scratch using dynamic programming.
  • Combine edit distance with word frequency data to create a probabilistic spell-corrector that ranks common words higher than rare ones.
  • Construct an interactive CLI that corrects misspelled text and explains its reasoning with distance, frequency, and combined scores.
  • Secret Mission: Enhanced the algorithm with QWERTY keyboard-distance weighting for smarter typo detection.

Ready to quiz yourself?