Heading

This is some text inside of a div block.
This is some text inside of a div block.
This is some text inside of a div block.
min read

Correct previous spelling error

Word • Macros • Editing • Functions
Peter Ronhovde
26
min read

Many spelling errors are quick flubs while you’re typing where you don’t necessarily want to take the time to go back and make the change. Even creating a quick shortcut to jump back to it will still be kind of slow.

Thanks for your interest

This content is part of a paid plan.

Correct Previous Spelling Error

If you’re like me, you can’t stand to see those little red squiggles as you type. It breaks my concentration like it’s mocking me. I know there is an edit feature where I can iterate through the errors, but I don’t want to wait. Writing sprint or not, the squiggles have to go! At least in my book.

AutoCorrect approximation

There is an AutoCorrect setting that will correct some spelling errors from the dictionary while you type, and you can add your own common misspellings (e.g., I added Ture for True because I kept messing it up). I use both of those features. However, they obviously don’t catch all errors, so let’s take the next step on the journey.

What’s the plan?

My current context is typing a novel and making a mistake. I’m in the flow, but those red squiggles pop under, and … My. Attention. Must. Fix. Error. I don’t want to take the time to move back and do so manually, so … let’s fix it right now.

Fortunately, most of the time, the first suggested spelling correction for is the right one, so why not let Word go ahead and make the change ... without touching the mouse. What do we need to do?

  • Find the previous spelling error within a reasonable document range
  • Get the collection of spelling suggestions
  • Replace the spelling error text with the first (presumably best) suggestion

A bonus case is similar:

  • If a spelling error doesn’t exist, correct any doubled spaces in the same range

Search range restriction?

“Huh?”

Before I leave you confused, let’s clarify a few points that may not be immediately obvious.

A range has collection of proof-reading errors for all errors inside the range.

“Okay—”

Just hold on. We’re not to the confusing part yet.

A Find operation is performed using a range variable (or the Selection), but it doesn’t stop a search within the used range. That behavior might seem intuitive given the errors collection is based on the spanned document range; however, the Find operation will continue searching through the document and update the used range variable to span any found text.

Not all words are in the standard or custom dictionaries, so in this macro, we want to restrict the search range to reduce any chances of an unintended correction. Toward this end, we create a second search range variable and ensure the found text range is inside it before we do anything else.

Previous spelling error

Limiting the search to somewhere within the previous portion of the page allows me to see the immediate change (I often write with a whole page visible on screen) and whether the change matched my expectations. Later, we’ll also see that it makes it easier to target the intended spelling error.

Using the first suggestion

We pick the first corrected spelling suggestion since this macro is intended to be a quick keyboard shortcut tap, and it’s done. I’m not interested in opening dialog boxes or jumping back to the error to manually fix it. My experience is the first suggestion is correct roughly 90% of the time, and that’s good enough for me.

Double spaces extra case

I added the doubled spaces correction because I consider that “like” a spelling error, so it fits the use case for this macro. They can annoy me about as much as a spelling error, so just fix the problem and move on. See the extended content below for more on this addition.

Create macro skeleton

Open the VBA editor (Option+ or Alt+F11) and create an empty macro.

Sub CorrectPreviousSpellingError()
' Insert macro steps ...

End Sub

Macros we assign to a keyboard shortcut can’t have any parameters or return values.

Define working range

To define the search range, which we’ll call rSearch, we start with the current page. A previous article talks more about using the special Word bookmarks, so we’ll be quick here. A bookmark is like a range in Word but with some extra stuff.

The fastest way to get the current page is to use one of Word’s hidden bookmarks named \Page. All the hidden bookmarks start with a backslash \. We use the Bookmarks collection of the Selection using double quotes for the bookmark name “\Page”.

Set rSearch = Selection.Bookmarks("\Page").Range

We get the corresponding page range using the Bookmark's Range property. We then Set this range equal to our search range variable.

Limit working range to previous content

The above range is currently the entire page. The intended use case corrects the previous spelling error, so we need to limit the extent of the range based on the user’s current location in the document. To accomplish this, we assign the end position of the Selection to the End position of the working range.

rSearch.End = Selection.End

No Set is required here because the End positions are just character position values in the document. I personally further tweak the search range based on the current paragraph, but this is good enough here.

Get spelling errors

Define a ProofReadingErrors variable:

Dim MyErrors As ProofreadingErrors

Yes, there’s an actual collection of proof-reading errors in Word. There are grammar errors and spelling errors, but we’re focused on spelling errors here.

This variable declaration isn’t strictly necessary (unless you’re using Option Explicit), but for such an unusual collection, I thought it was clearer to include it.

Since we’re dealing with an object that’s not a regular value, we need to Set it equal to the SpellingErrors collection. Our working range rSearch has a collection of included spelling errors which may be empty.

Set MyErrors = rSearch.SpellingErrors

We’re storing the errors collection in the MyErrors variable.

Fix spelling error

Correcting the error is a little more complicated than using the context menu, or whatever other approach, because we want to correct it automatically. It takes a little work to sort all this out before correcting the spelling error.

Check error count

What if there are no spelling errors detected or any suggested corrections?

Obviously, there is nothing to do if there are no spelling errors found in our restricted search range. We can check that using the Count property of the errors collection.

NErrors = MyErrors.Count

This stores the total number of errors in the rSearch range for convenient use below. As a mnemonic, I will often add a prefix for any number-related variable with a lower-case or capital N. It also shortens the variable names.

If NErrors > 0 Then
' Determine previous spelling error and any suggestions ...

End If

The If statement ensures we only proceed with any changes if we find at least one prior spelling error. Otherwise, we just exit the macro.

Get last spelling error

The last spelling error range in the search range is the one just prior to our current typing location. Based on the restricted rSearch range, this is the last error in the collection.

Set rError = MyErrors(NErrors)

The parentheses notation used with a collection picks the spelling error at that particular number of the collection. NErrors is the total number of errors, so it is the last error in the collection. Working with only the prior spelling errors on the current page made it easy to identify the spelling error immediately before our typing location.

For an error collection, this reference returns a document range corresponding to that particular error which we're storing in the rError range variable.

To be extra clear, MyErrors is the collection of ranges including the spelling errors in the rSearch range. The rError variable above is the document range corresponding to the last spelling error.

Alternative with GoTo command

In general, a more direct method to get the previous spelling error would be using a GoTo method with a command something like the following:

Set rError = rError.GoToPrevious(What:=wdGoToSpellingError) ' Example not used

But in this macro, we already have the restricted search range, so we just immediately accessed the last spelling error in the range. This also allowed us to avoid additional verifications that the found grammar error is in the search range.

Get spelling suggestions collection

What is the correction text?

We first need the collection of possible suggestions. Any suggestions are returned by the GetSpellingSuggestions method of the error range defined above.

Set Suggestions = rError.GetSpellingSuggestions(IgnoreUppercase:=True)

We tell the method to IgnoreUppercase by assigning True to the option since we don’t want case to matter.

The Suggestions variable is being Set to a collection of suggested spellings of whatever misspelled word is in the rError range.

Get spelling suggestions

We need at least one spelling suggestion before we continue. Otherwise, we have nothing to use for the automated correction. Get the total number of suggestions using the collection’s Count property.

NSuggestions = Suggestions.Count

Make sure we have at least one suggestion before proceeding.

If NSuggestions > 0 Then
' Fix spelling error if any suggestions exist ...

End If

Get correction text

Setting up to make the text change, we first identify the suggestion text.

SuggestionText = Suggestions(1).Name

This picks the first suggestion in the Suggestions collection using the number one in parentheses (1). A suggestion’s plain text value is stored in its Name property.

Fix spelling error

Finally assign the correction text to the spelling error text.

rError.Text = SuggestionText

This is a plain text change not respecting any formatting other than perhaps adopting formatting of the first character in the document at the text location.

Gotchas

Where could all this go wrong?

What if there are no spelling errors or suggestions?

The first If statement checks whether any spelling errors exist, so if they don’t, nothing happens. Same goes for no suggestions. With the checks performed in the macro, nothing happens in the document if no errors or suggestions exist.

However, when using the macro, this can be a little disconcerting at first because you might wonder whether you actually tapped the keyboard shortcut correctly. In my opinion, this behavior is far more preferable than having to dismiss a dialog box that pops up. I could always just tap the keyboard shortcut again to be sure.

What if the spelling correction isn’t what I wanted?

That definitely happens occasionally. The top suggestion in the list is correct much of the time, but if my spelling is particularly atrocious for that word (missing the first letter seems to cause the most trouble), it can misread our intended word. In that case, I usually just undo the correction, and I have a supplementary macro to jump to the previous spelling error where I can manually make the change. Alternatively, I just undo the correction and ignore the error until the next edit. It just depends on my mood at the time.

Final Macro

Putting everything together, the macro is:

Sub CorrectPreviousSpellingError()
' Correct previous spelling error within current page

' Get current page range and restrict to previous text
Set rSearch = Selection.Bookmarks("\Page").Range
rSearch.End = Selection.End ' Limit to previous text

' Get spelling errors collection from above search range
Dim MyErrors As ProofreadingErrors
Set MyErrors = rSearch.SpellingErrors

' Only proceed if at least one spelling error exists
NErrors = MyErrors.Count
If NErrors > 0 Then
' Set range of previous spelling error
Set rError = MyErrors(NErrors)

' Only make change if at least one suggestion exists
Set Suggestions = rError.GetSpellingSuggestions(IgnoreUppercase:=True)
NSuggestions = Suggestions.Count
If NSuggestions > 0 Then
' Get first spelling correction text
SuggestionText = Suggestions(1).Name

' Make correction
rError.Text = SuggestionText
End If
End If
End Sub

I assigned this macro to Command+Shift+F7 in Word for Mac or Control+Shift+F7 on Windows. I override a standard function key shortcut because I rarely use most Word's default function key shortcuts.

What about grammar errors?

Grammar errors don’t correspond to word-related suggestions in the same way as spelling errors, and VBA does not give us access to the specific grammar errors in the same way as spelling errors (the whole sentence range is returned). It is likely not currently possible to replicate or extend the above macro for grammar errors.

However, if you use the default Word keyboard shortcut Option+F7 or Alt+F7, you can jump to the next grammar error. Word will immediately offer suggestions in a context dialog ready to apply, usually just by pressing Enter. It’s not as nice as just making the change and moving on, but on the other hand, grammar errors often require more of a human touch anyhow.

Fix Previous Double Spaces

This is a smaller addition (but more steps) to the automated spelling correction above since I sometimes accidentally add doubled spaces also.

Other Functions

To complete the macro below, we'll need a few assistant functions. They aren't strictly necessary, in general, but they make writing the macro easier and cleaner.

We also use If-ElseIf statements below, so if you'd like an introduction or a basic refresher on conditional statements, check out this introductory article.

Additional working range

We established the working search range rSearch earlier. A second working range will start with the current Selection Range.

Set r = Selection.Range
r.Collapse Direction:=wdCollapseEnd

This is basically the current typing position in the document. We’ll use it to search for the doubled spaces with the Find method. Since we’re searching backward, we collapse toward the end of the Selection, so we don’t miss anything.

Setup Find parameters

I won’t go through every Find parameter option below, but I like to list anything relevant to clearly define the search and avoid any unexpected issues.

With r.Find
.ClearFormatting
.MatchWholeWord = False
.MatchWildcards = False
.MatchCase = False
.MatchPrefix = False
.MatchSuffix = False
.Format = False
.Forward = False
.IgnoreSpace = False
.Wrap = wdFindStop
End With

This uses a With statement since we’re referring to many Find parameters at once. With statements allow us to omit the r.Find reference for all settings inside it.

Most of these make sense for a spaces search. For example, we can’t ignore spaces. Most of the other settings are just to be careful, but two are more relevant.

We’re searching backward, using .Forward = False since the use case mentioned earlier was correcting recent document errors while writing a novel. The .Wrap = wdFindStop settings doesn’t allow the search to wrap around from the end of the document. Although, technically this one is superfluous since I restrict the found text to the search range.

Do the search

The Find operation is performed using the Execute method of the Find property.

r.Find.Execute FindText:=" ", Replace:=wdReplaceNone

The FindText is literally two spaces in double quotes “  ”. We are not replacing the text, thus the wdReplaceNone value for the Replace option.

After the command executes, the Find operation will select the relevant text as the new working range r, so we can do something with it. As a reminder, the search is not restricted to the starting range. It will continue through the document trying to find a match according to the rules given to the Find command.

Check working range extent

We need to know if the find operation was successful which is determined using the Found property.

r.Find.Found

This condition is True if the search was successful and False if not.

Constraining the search

The Find operation will continue through any defined range into the rest of the document. In my use case, I don’t want to be jumping back to seemingly random locations in the document, so I restrict my search to the previously defined search range rSearch.

If the found text is inside the previous page range rSearch, then delete the doubled (or more) spaces. Fortunately, there is already an InRange method to detect such a condition.

r.InRange(rSearch)

This method returns True if the range r is inside the argument range rSearch (the one in parentheses).

Our condition requires both a successful Find action to be True and for it to occur in the constrained page range. Since both must be True to proceed, this requires a Boolean And operator.

If r.Find.Found And r.InRange(rSearch) Then
' Found, so remove excess spaces ...

End If

Extend range over excess spaces

There’s no sense leaving other spaces if there are more than two, so expand the range to include any additional spaces. Our initial search was backward, so the working range r would necessarily find the two right-most spaces in any gap.

rSearch.MoveStartWhile Cset:=" ", Count:=wdBackward

We’ve used MoveStartWhile multiple times through this blog, but briefly it moves the beginning of the range while it keeps finding any characters given in the Cset option which is given as a space " " here (double quotes are required to define regular text for the character set). In this command, the Count option tells the command to move the Start position backward in the document.

Now we know we’ve included all local spaces in whatever gap exists.

Delete spaces conditions

We could just delete the doubled spaces, but I like my macros to handle the different cases naturally within reason. What are the various cases?

  • If the next character is a paragraph mark, delete all spaces.
  • If the next character is a sentence punctuation mark (most of them, see below), delete all spaces.
  • If the next character is any other character, delete all but one of the spaces.

Unfortunately, this is a little trickier than it seems at first glance.

Negatory on reducing to two conditions

You might want to combine the first two conditions since they have the same result (delete all spaces in the range), and normally this would be logical since they correspond to the same action, but there is a confounding issue for the end of a paragraph that makes it a separate case (see below). There is a way around it, but I felt like this was the clearest solution.

ElseIf statements

We have three possible conditions above, so we need an If-ElseIf statement (see article introducing conditional statements). A whirlwind introduction to the If-ElseIf statement follows.

An If-ElseIf is essentially a chain of If statements with another keyword ElseIf joining them together.

If ConditionOne Then
' Do these steps if condition one is True ...
ElseIf ConditionTwo Then
' Do these steps if condition one is True (but condition two is False) ...
Else
' Do these steps if both condition one and condition two are False ...
End If

We can chain more ElseIfs in the middle section, but if it gets too long, you should probably consider a Select statement instead since they’re designed for longer decision branches.

How it works

If the first condition is False, then check the next one, and repeat until no more ElseIfs are present. Once a branch is selected based on the first one with a True condition, run those steps and ignore all other branches regardless of their condition values. If all conditions are False, do the Else steps if they’re included just like a regular If statement.

Basic idea for our problem …

For our particular problem, the branches would be something like:

If next character is a paragraph mark Then
' Delete all spaces at end of paragraph ...
ElseIf next character is some other sentence punctuation Then
' Delete all spaces since next character is some other sentence punctuation
' (but not a paragraph mark) ...
Else
' Delete all but one space ...
End If

Of course, we need to replace the words with actual logical conditions and decide on the specific steps to take in each branch.

Get next character

We first need to get the next character after the spaces range for our testing. This is easy since we know we have a range with something in it.

We technically don’t have to declare the NextCharacter variable yet, but we’ll need it later to pass it to a function, and it needs to be declared before we use it.

Dim NextCharacter As String

In general, a String can contain more than one character, but we’re picking it to correspond to a single character.

We’ve used the Next method several times. It returns the next Unit given, and we specify wdCharacter here. The default Count is 1 which is what we want. We store the value in the NextCharacter variable which is one reason why we needed to include the Unit option in parentheses.

NextCharacter = r.Next(Unit:=wdCharacter)

The Next method returns a range, but we want the actual character, so we reference its Text property at the end.

NextCharacter = r.Next(Unit:=wdCharacter).Text

Paragraph ending

Recall a paragraph ends with the special paragraph mark character vbCr.

Checking for the paragraph ending is easy. Just compare the known NextCharacter variable to vbCr.

Unfortunately, correctly deleting the space can be a little complicated for certain cases because Word likes to automatically adjust the spacing for us even while our macro is running. We’ve previously written a function to overcome this tiny but annoying issue, so we’ll take advantage of it here.

If NextCharacter = vbCr Then
' End of paragraph so delete spaces
Call DeleteParagraphEndSpaces(r.Paragraphs.First)
' Continue If-ElseIf statement below ...

The DeleteParagraphEndSpaces function deletes any extraneous spaces at the end of a given Paragraph (not a Range), so we give it the First paragraph of the working range r using its Paragraphs collection.

r.Paragraphs.First

This paragraph is not actually within the range r, but the function doesn’t know or care. It just works with the given paragraph. Check out the previous function if you’re curious. As simple as the task sounds, it ends up taking several steps to correctly complete in all cases.

Sentence end

Word doesn’t seem to cause any trouble (by adding spaces back without our knowledge) when we’re deleting spaces at the end of a sentence, so just delete the whole range of spaces.

With that in mind, we need to know whether NextCharacter is a sentence ending punctuation mark.

Other punctuation

However, we can easily generalize this condition to allow for other punctuation marks that are also not preceded by a space like dashes, an apostrophe, a comma, etc. For lack of a better brief description, we’ll refer to these as “right” punctuation marks in analogy with right double quotes. See the previous function for this simplifying function.

We pass the known NextCharacter to the function for the test.

IsRightPunctuation(NextCharacter)

This function returns true if it finds a punctuation mark indicated by NextCharacter isn’t usually preceded by a space or paragraph mark.

This function call is also why we needed to explicitly declare the NextCharacter variable earlier. If not declared explicitly, VBA would complain and not run the function (see earlier article for a more explanation).

Delete spaces at punctuation marks

Now use the punctuation mark function to decide whether to delete the spaces.

' Continued from If-ElseIf statement above ...
ElseIf IsRightPunctuation(NextCharacter) Then
r.Delete ' just delete spaces in range
End If
' Continue rest of If-ElseIf below ...

This looks simple because the IsRightPunctuation function did the checking for us, so it is just a quick function call.

Other next characters

For any other characters, we delete all but one space. Since the range currently contains only spaces, we can just move the Start position and remove the first one.

' Continued from If-ElseIf above ...
Else
r.MoveStart ' leave one space
r.Delete ' delete rest of spaces in range
End If

We could also just replace the Text property with a single space. It just a matter of preference.

Delete doubled spaces snippet

Putting the double space code together, we have a long snippet of code which we include inside an Else part of the original If statement in the macro above.

Combined Macro

This is the extended version of the macro combining the spelling and double space corrections.

Sub CorrectPreviousSpellingError()
' Correct previous spelling error within current page
' Or delete any previous doubled spaces in the page range if a spelling
' error is not found

' Get current page range and restrict to previous text
Set rSearch = Selection.Bookmarks("\Page").Range
rSearch.End = Selection.End ' Limit to previous text

' Get spelling errors collection from above search range
Dim MyErrors As ProofreadingErrors
Set MyErrors = rSearch.SpellingErrors

' Only proceed if at least one spelling error exists
NErrors = MyErrors.Count
If NErrors > 0 Then
' Set range of previous spelling error
Set rError = MyErrors(NErrors)

' Only make change if at least one suggestion exists
Set Suggestions = rError.GetSpellingSuggestions(IgnoreUppercase:=True)
NSuggestions = Suggestions.Count
If NSuggestions > 0 Then
' Get first spelling correction text
SuggestionText = Suggestions(1).Name

' Make correction
rError.Text = SuggestionText
End If
Else
' Look for prior doubled space if no prior spelling error is found
Set r = Selection.Range
r.Collapse Direction:=wdCollapseEnd

' Define search parameters
With r.Find
.ClearFormatting
.MatchWholeWord = False
.MatchWildcards = False
.MatchCase = False
.MatchPrefix = False
.MatchSuffix = False
.Format = False
.Forward = False
.IgnoreSpace = False
.Wrap = wdFindStop
End With

' Do double spaces search
r.Find.Execute FindText:="  ", Replace:=wdReplaceNone

' Delete spaces if detected within search range
If r.Find.Found And r.InRange(rSearch) Then
' Get all spaces nearby
r.MoveStartWhile Cset:=" ", Count:=wdBackward

' Check next character before deleting anything
Dim NextCharacter As String
NextCharacter = r.Next(Unit:=wdCharacter).Text
If NextCharacter = vbCr Then
' End of paragraph so delete spaces
Call DeleteParagraphEndSpaces(r.Paragraphs.First)
ElseIf IsRightPunctuation(NextCharacter) Then
r.Delete ' just delete spaces range
Else
r.MoveStart ' leave one space
r.Delete ' delete rest of spaces in range
End If
End If
End If
End Sub

I assigned this macro to Command+Shift+F7 in Word for Mac or Control+Shift+F7 on Windows. I override a standard function key shortcut because I rarely use most of the default Word function key shortcuts.

Copy and paste warning

If you copy the above macro (which is welcomed for individual use), HTML formatting often collapses repeated spaces such as the doubled spaces in the Find.Execute FindText option. I used two non-breaking spaces as a workaround for this issue (a non-breaking space is a different character than a regular space). In testing, this seemed to circumvent the space collapse by HTML since the editor appeared to translate the non-breaking space into a regular space during the text paste. To be safe though, after you copy it into the VBA editor, you should manually verify the FindText option is a double regular space in double quotes before using the macro.

VIP technical support

Sometimes debugging more complex macros can feel like playing a Whack-a-Mole game especially as you add new and improved features. Premium members get access to special VIP links for limited technical support as specified in the member benefits [please note support time does not accumulate since I cannot overcommit future scheduling requirements (but I try to be reasonable about it) nor cash out in any way if membership ends or is downgraded; support does not consist of writing entire macros or functions which would instead qualify as a paid service].

Affiliate Links

If you're interested in using Word or another tool related to the article, check out these affiliate links. I may make a small commission if you purchase when using them, but there is no increase in cost for you, and it helps to support this site and associated content.

I've been using Microsoft for Business for commercial use (that's us writers) on one of the lower pricing tiers for years. I get to use my macros, have online storage, and don't have to worry about software updates.