Text manipulation macros occasionally need the next character after a range. While it’s a trivial subtask in principle, it requires several steps to obtain the intuitive choice for any range variable. It occurs often enough it is convenient to have a dedicated function for the subtask.
Thanks for your interest
This content is part of a paid plan.
Get the next character after a range
If a range spans any text in the document, the next character is obviously the one immediately after the range ends. That makes sense. Unfortunately, the “next” character after a range depends on whether the range is empty or not.
An empty range is one where its Start and End positions are equal. The next character would intuitively be the character immediately after the end of the range, but VBA considers that character to be in the empty range. This is unintuitive and inconsistent with how a non-empty range works, so this function remedies this inconvenient situation.
This function is a small part of a series of articles designed to streamline a pair of move sentence macros, but this one is quite general. A sibling member version returns the next character range, but we often just need the character, so this version returns the text. This is convenient for some use cases, but both versions are useful.
Create the empty function
Open the VBA editor with Option+F11 in Word for Mac (or Alt+F11 in Windows) and create the following empty function.
The single quotes are comment characters where any text on the same line after them is ignored by VBA.
What parameter do we use?
The function needs a document range after which we want to identify the next character. The function is brief, and we only need a single working Range, so we use a simple parameter name of just r. No changes are made to the parameter inside the function, so we don't need to worry about any changes leaking out of the function. See our introduction to functions and subroutines article for more explanation.
What is the return result?
The next character text is returned as a String. While VBA can declare fixed-length String types, there is no benefit to returning a fixed-length String in this function.
What’s the plan?
We just need to test whether the range is empty and return the intuitive next character based on the range argument r given by the user. More specifically, the returned result will be:
- If r is empty, return the first character as the intuitive next character.
- If r is valid, return the next character after the range (the regular case).
- If r is invalid, return an empty string "".
An empty string is a reasonable invalid value since the only range in the document that does not have a next character is the position after last paragraph mark in the document.
Rough conditional statement for an empty range
The basic decision logic to pick the correct character would look something like the following:
That seems simple enough, but the details get a little tricky. It's not difficult, but we need to be careful.
How do we test if a range variable is empty?
VBA plays loose with how it treats an empty range variable compared to a range that spans content, so we need a reliable way to detect it. What's the problem?
Character count does not work
Detecting an empty range based on how many characters it contains makes sense. A range containing zero characters would logically indicate it's empty, and a range containing one character should indicate the range … spans a single character.
Hmmm, so far so good.
We can access the character count information with the Count property of the Characters collection.
Unfortunately, the character count doesn't work as expected since an empty range is treated as if it contains one character. A range literally spanning one character also contains one character. If these ranges have the same Start position, it is the same character.
Ughhh.
So, we can’t check whether a range is empty by checking how many characters are spanned. It's an example of why we need to be a little careful when working with empty ranges in Word VBA.
Use Start and End positions
Instead, we can check whether a range is empty by comparing its Start and End positions.
In Word VBA, Start and End are literal character positions counting from 0 at the beginning of the document. If the two position values are the same, it spans no text in the intuitive sense, so the range is empty.
This is a True or False (Boolean) condition checking whether the two numbers are equal. VBA will interpret it as a Boolean value in a conditional statement.
Get the first character text
The first character range is found using the First property of the Characters collection.
Our function is returning the character as text, so we need to reference the Text property of the character range.
Assign the first character result
We assign this character to the function name as the final result.
Whatever value it has at the end of the function is the returned result.
Get the next character text
If the range spans any text in the document, we instead use the Next method to get the next character range.
The Next command returns a range corresponding to the Unit given. Of course, we specified wdCharacter. We also put the Unit option inside parentheses since we need to access that range’s Text property to get the next character. However, a character is the default unit, so we can just omit the unit option for a cleaner command.
Assign the next character result
We again use the Text property and assign it to the function name as the result.
Intuitive next character conditional statement
Putting the conditional steps together, we get the intuitive next character.
We just stored the text value in the function name as the respective return value, but a result is returned either way.
Gotchas
This function is simple, but we should still think about potential problems.
What if the given range doesn’t exist?
This is a common consideration for any function or subroutine that receives external data. What if the user gives us a range variable that isn’t yet assigned to a document range?
To be safe, we should add a few steps to check whether the range exists and just exit the function if not.
What is Nothing?
We don’t want to wax philosophical or veer too far into technical, but “Nothing” in VBA is assigned to an object that isn't yet assigned to a valid document element (or whatever the data type represents). Nothing is not a value in the normal sense like 0 or -1.
Comparing objects in VBA
VBA does not use an equals = sign to compare objects such as two Range variables. Instead, it uses the keyword "Is" to check whether two objects refer to the same thing. Without getting into the details of exactly what that means, we literally use the phrase “Is Nothing” as a condition to check whether a variable is not assigned to something in the document.
Assign a reasonable invalid function result
The function still expects a return value, so we need to assign a result that makes sense and implies the user gave it an improper argument.
Since we found no next character, a literal empty string "" (no characters are inside the double quotes) makes the most sense, and it communicates to whoever is using the function that something went wrong.
Quit the function
Now, we quit the function.
The Exit Function command quits the function immediately. No steps after the command are run which is why we needed to assign the return value before giving this command.
Invalid range conditional statement
Putting it together, our range validation is:
Invalid range check placement
The placement of the validation check is important. We need to check whether the given range is Nothing before we try to use it for anything else. Otherwise, we’ll get an error because any other use would be attempting to reference an invalid range.
This extra validation is an example of being able to (or needing to) add extra safeguards in a dedicated function, but it doesn't clutter our external macro with extra steps. Often in a bigger editing macro, we already know a range is valid based on prior steps, so we could omit this validation in that context. Such tiny inefficiencies would almost never be noticed in a Word editing macro, but we get a much clearer main macro in exchange.
Final get next character text function
The function is small but useful, and it will save multiple steps in other macros.
It's unfortunate that such a simple concept requires that many lines, but the function keeps them neatly contained. In another macro, we can just use the function as a logical subtask knowing we'll get the correct character. If we just need the range of the character, use the sibling member function. It further implements the function with a default range based on the initial cursor position.
How do we use the function?
The functions is easy to use, and we just call it where needed.
Assign the function result to text variable
We declare an example variable for the explanation.
We can simply assign the function result to the variable.
Selection.Range is the current cursor position in the document specified as a document range, but we could pass any range to the function.
Use the function result in a conditional statement
We could also just use the character directly in a conditional statement
The function simplifies the condition. We don't need any extra steps such as assigning an intermediate variable storing the next character text.
Improvements?
Is there anything we can do better?
As illustrated above, a common use case is probably finding the next character after the cursor position in the document. Using Selection.Range is wordy, so it would be nice if the function assumed it unless we specified otherwise. While it's not difficult to do, implementing a default starting range is a little messier than it appears, so it's relegated to a separate member article to get the next character range.