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

Get the next character text

Word • Macros • Functions
Peter Ronhovde
11
min read

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.

Function GetNextCharacterText(r As Range) As String
' Get the next character text after r in the intuitive sense
' Include the function steps ...

' Return the next character text
GetNextCharacterText = "" ' Placeholder result
End 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:

' Get the next character immediately after the working range
If the given range is empty then
' Range is empty, so use the first character ...
Otherwise
' Range is not empty, so use the regular next character ...
End the empty range check

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.

' Does not work for detecting an empty range ...
r.Characters.Count ' How many characters are in the range?

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.

r.Start = r.End ' Condition checking whether a range is empty

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.

' Get the first character range
r.Characters.First ' Not done ...

Our function is returning the character as text, so we need to reference the Text property of the character range.

' Get the first character text
r.Characters.First.Text

Assign the first character result

We assign this character to the function name as the final result.

' Return the first character text for an empty range
GetNextCharacterText = r.Characters.First.Text

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.

r.Next(Unit:=wdCharacter) ' 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.

r.Next ' Not done ...

Assign the next character result

We again use the Text property and assign it to the function name as the result.

' Return the regular next character text
GetNextCharacterText = r.Next.Text

Intuitive next character conditional statement

Putting the conditional steps together, we get the intuitive next character.

' Get the next character text immediately after the given range
If r.Start = r.End Then
' Range is empty, so use the first character ...
GetNextCharacterText = r.Characters.First.Text
Else
' Range is not empty, so use the regular next character ...
GetNextCharacterText = r.Next.Text
End If

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.

If the given range is not yet assigned to something valid then
' Assign a reasonable invalid function result ...
' Exit the function immediately
End the valid range check

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.

' Assign an invalid function result
GetNextCharacterText = ""

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.

Exit 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:

' Check whether the range r exists and exit if not
If r Is Nothing Then
GetNextCharacterText = ""
Exit Function
End If
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.

Function GetNextCharacterText(r As Range) As String
' Get the next character text after r in the intuitive sense
' Returns an empty string if the range r is invalid

' Check whether the range argument r exists and exit if not
If r Is Nothing Then
GetNextCharacterText = "" ' Invalid return result
Exit Function
End If

' Check whether the working range is empty and return the intuitive
' next character text
If r.Start = r.End Then
' Range is empty, so return the first character text
GetNextCharacterText = r.Characters.First.Text
Else
' Range spans some content, so return the next character text
GetNextCharacterText = r.Next.Text ' Default unit is a character
End If
End Function

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.

' Declare a temporary variable for the next character text
Dim sNext As String ' Optional

We can simply assign the function result to the variable.

' Get the next character text after the cursor position
sNext = GetNextCharacterText(Selection.Range)

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

' Example of using the function directly in a conditional statement
If GetNextCharacterText(Selection.Range) = ")" Then
' Next character is a right parenthesis, so do something ...
End If

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.

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.