I like to move around my document faster using targeted navigation, and navigating by common punctuation marks is one way to accomplish this.
Thanks for your interest
This content is part of a paid plan.
Simple Versions
If you didn’t see the earlier article covering Word VBA macros for jumping to punctuation marks in your documents, the results are below. Also refer to the first article for setup and explanation of the basic steps.
Moving
Moving forward to the next comma in the document:
Moving backward in the document:
Selection
The movement macros are easily modified to allow us to select all text up to the punctuation mark by modifying the Start of End of the Selection rather than just the insertion point location.
Selecting forward in the document is done by:
Select backward in the document:
You can modify the Cset character strings (characters at which the command stops the search) in each case to search for other punctuation marks or even include multiple search characters.
I’ve created variants for several common punctuation marks like periods and parentheses. Additional enhancements are covered in this article.
To be more concrete, we’ll refer to commas for the majority of the text below.
Iterating through the document
Suppose you select all text from the current edit location up to the next comma in the document.
If you tap the keyboard shortcut again. The basic macros above won’t select any additional text since the macro immediately “finds” the comma and stops the character search.
This doesn’t feel intuitive to me.
I personally like my macros in this context to jump to successive punctuation marks if I repeatedly press the keyboard shortcut like the following selection example.
While the above macros are simple and a great place to get started, only GotoPreviousComma allows me to iterate the process as desired. That one works only because I prefer to end the macro on the left side of the comma regardless of which direction I'm moving through the document. For the others, you have to manually move past the comma before jumping or selecting to the next one.
So I want to add steps to my macros to make them behave the way I want. That’s one of the macro super powers if you’re willing to do some work up front.
The changes are mostly easy to implement. Unfortunately, there are a couple gotchas, but that’s why I’m here to help.
How do we iterate to the next comma?
The basic steps are straight forward. When the user runs the macro:
- Detect whether there is a comma next to the current insertion point (i.e., the edit location)
- If there is a comma immediately next to the current location, move past it by one character (or extend the selection past it for the selection macros).
- Jump to the next comma (works whether or not a comma was detected first)
Seems simple enough …
You don’t have to write everything out like this (I’m writing an article after all), but thinking through specific steps like this might helps ensure you aren’t missing any obvious or less-than-obvious steps or other issues.
As advertised, the steps aren’t difficult, but the specifics get a little tricky when moving or selecting forward based on how Word views the text contents of empty versus non-empty selections.
That’s just how these particular commands work, so we’ll have to dig through the details a little moving forward.
Next character problem
A small issue with the steps above is determining the next character. It doesn’t seem like it should be an issue, but it doesn’t work the same way every time.
Doing some testing, we might notice the difference occurs depending on whether there is a starting selection or not.
We get different “next” characters in each case which is a problem if we want our macro to work correctly every time.
Next character method
The most intuitive method for getting the next character is probably the Selection.Next method. Let’s cover it briefly since this may be new to some readers.
This command tells VBA to “return” the next chunk of text after the Selection in whatever unit I specify. It defaults to a character, so I can leave out the Unit for our macros today.
These can't be used all on their lonesome like this. We need to store them somewhere (see below).
Next Unit and Count
Along with a Unit, we could also give a Count, like Count:=3, argument perhaps if we wanted to know the third character after the Selection rather than the first, but this apply to our current macros.
One difference between this Next command and several we’ve covered previously is we wrapped the Unit argument in parentheses because we need to follow the Next method with the Text property.
Otherwise, the Next method returns a Range in the document not the text. The distinction is subtle, but we’ll cover Ranges later (they’re often a better way to solve problems in VBA macros compared to using the Selection object directly).
Storing values in variables
Back to our macro solution. Once I have the Next character, I want to store it in a clearly named variable for later reference:
For whatever reason, VBA uses an equals = when we are storing a value in a variable, but it uses a := symbol when we assign values to parameters for commands (like with Unit:=wdCharacter above). I would have liked more consistency, but that’s how VBA works.
Using the next character
Now that we supposedly have the correct next character after the Selection. We want the macro to skip a comma if it is at the edit location:
We’ll cover conditions using If statements in another article, so I can’t discuss it in detail now without bogging down the (already long) solution here. Suffice it to say that it allows to to make a decision in the macro on whether to run some steps based on a condition we choose.
The above macro steps work if at least one character of text is selected (where Selection.Start is less than Selection.End in the document).
The problem ... empty selections
But it doesn't work when there is no selection (Selection.Start is the same as Selection.End).
Why?
When there is no selected text, the Next command will return the second character after the cursor location.
What?!
We get two different characters depending on whether a selection exists or not. This inconsistent behavior makes creating a reliable macro more troublesome.
Apparently, Word considers even an empty selection to contain at least one character. I’m sure they have a reason, but I find this behavior a little confusing. In my opinion, it’s more intuitive to think of an empty selection as containing no characters.
Even if it's inconsistent, it’s how VBA works, so we have to accommodate it. The solution isn’t too bad though.
Next character solution
As with many problems, there are at least two ways to solve it, and the choice is often a matter of preference. I’ll pick the method that works most consistently for the macros above. If you’re interested in other methods, let me know.
Now that we know the problem, how do we get the character immediately to the right of an empty selection?
Simple actually. Word VBA apparently assumes the first character after an empty selection is nevertheless part of the Selection text.
Note Selection.Text normally returns the entire selected text, but importantly for our purposes here, it returns the character at the cursor location when there is no selection.
Getting the next character every time
What are some fool-proof steps to get the next character in the intuitive sense regardless of whether there is a selection or not?
- Check whether there is a selection
- If there is a selection, get the next character with the Next method
- Otherwise get the next character using the Selection Text
- Store the character in either case
Now continue with the other steps mentioned earlier.
- If the next character is a comma, move past it (or extend the selection past it for the selection variant).
- Jump or select to the next comma as normal
What kind of selection?
To check whether there is any selected text, we have to check the "Type" of Selection.
There are several types of selections (block, shapes, tables, etc.), but we'll cover the topic in more detail later. Here we basically want to know whether or not there is a "normal" selection.
The Word constant that indicates just that is wdSelectionNormal, so we just check the Selection Type against it:
Sometimes it is more convenient to check if there is not a selection. Without any explanation here, the constant for that is wdSelectionIP.
There are some gotchas to watch out for, but we'll have to relegate those to a separate article.
Macro steps
In VBA, these steps look like:
This method of getting the next character begs for a function, but that is a lesson for another day.
For the SelectToNextComma variation the last steps instead use:
Previous comma version?
What changes when jumping to the previous comma?
We don’t have to worry about the next character issue since the previous character is consistent regardless of whether there is a selection or not.
With that in mind, we get the previous character using:
Again, we omit the Unit within parentheses since it defaults to returning the next character.
Final Macros
Move variations
Putting the above steps together, our macro to jump to the next (or successive) comma in the document is:
The variant to go to the previous (or successive) comma in the document is:
Selection variations
For the selection variations, the basic steps of the macros are the same, but we replace the move commands with MoveStart or MoveEnd variations as follows:
Selecting backward through the document: