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

Range intersection

Word • Macros • Functions
Peter Ronhovde
10
min read

In some macros, it’s useful to know the overlap, or lack thereof, of two distinct document ranges in Word.

Thanks for your interest

This content is part of a paid plan.

Range Intersection Function

A function finding the intersection of two Word ranges would be more natural as a native Range method, but that does not exist in Word VBA, so we need a separate function.

What does an intersection mean in Word?

A mathematical intersection includes all shared elements between two sets. The equivalent for Word ranges is finding the overlapping document positions of two ranges.

Of course, two sets might have no elements in common, so the intersection would be the empty set. We’ll also need an equivalent for Word range intersections (see below).

Brief review of positions and ranges

Remember document positions are the number of characters counted from the beginning of the document. Ranges in Word are essentially stored as Start and End positions in the document.

Why should I care?

As an author, I try to play safe with my macros, particularly if there is a function that has the potential to affect a large portion of my document. In such cases, I’ll restrict the working range to limit any ill effects if something goes wrong.

For example, an upcoming macro adds all unknown words in the selection to a custom dictionary, but have you ever accidentally selected a larger region of the document than you originally thought? I don’t want to accidentally add all misspelled words to my custom dictionary, so constraining the initially selected range to within the current page helps prevent any mishaps. Of course, I also give a user the option to force any changes, if desired, so it’s a precaution not an essential feature.

Different from InRange method

If you just want to know whether one range is fully inside the other, then the existing range method InRange returns a True or False value.

r1.InRange(r2) ' Contained inside, not an intersection

This is True if range r1 is inside r2 and False if not. I’ve used this method to restrict Find operations to within a target range.

Create the function skeleton

We start by creating the function skeleton.

Function IntersectRanges(r1 As Range, r2 As Range) As Range
' Include function steps ...

' Return overlapping range
Set IntersectRanges = r ' r is a working range
End Function

What parameters to use?

The function accepts two ranges, which we’ll call r1 and r2, to check for any overlap between them.

Return type

We return the overlapping document range, if any.

We can further indicate an empty set equivalent with no overlapping document range using a “Nothing” value, so return Nothing if either given range is Nothing or if there is no intersection.

Special cases

We first need to handle a couple special cases.

What about an empty range argument?

This is an extra foolproof check, but it must be done since we can’t guarantee a macro won’t give us an invalid range variable.

In Word VBA, an unassigned range variable has a “value” of Nothing meaning it hasn’t yet been assigned a proper document range. If either range r1 or r2 is Nothing, there is no possibility for an intersection between the ranges, so we assign Nothing as the function’s return value and immediately exit the function.

Set IntersectRanges = Nothing
Exit Function

Since it's a range, we need to use Set to assign it, but we literally assign Nothing to it.

Nothing has other uses in Word VBA like effectively deleting an object. Today we’re using it to indicate the equivalent of an empty set result for our intersection.

Detecting Nothing

How do we detect Nothing?

The condition to detect an unassigned object has a special syntax.

SomeRange Is Nothing

Notice the “Is” statement instead of a more typical equals = sign in regular value conditions. This condition is True if the variable SomeRange is not yet assigned to a valid document range. This example refers to a Range variable, but the idea also applies to other object types.

We need to two of these for the given ranges r1 or r2 since either of them being Nothing is enough to invalidate a possible intersection between them.

If r1 Is Nothing Or r2 Is Nothing Then
' At least one given range is already Nothing ...
End If

In order to make it past this If statement, both conditions must be False meaning both ranges must exist in the document.

What if there is no overlap?

Technically we don’t need to check for no overlap this early in the macro, but it makes the later logic a little simpler since we can assume at least some overlap exists even if only at one document position.

We take advantage of the fact that ranges in Word are essentially a span of contiguous character positions in a document.

What is the condition for no overlap?

Due to the ordered nature of Word range positions, there is no overlap if range 1 ends before range 2 starts. More specifically for VBA ranges, the End position of range r1 is before the Start of range r2.

r1.End < r2.Start

Since we don’t know which range is earlier in the document, we also need to check the reverse condition where r2 is before r1.

r2.End < r1.Start

If either condition is True, the result is an empty set. This sounds like another Boolean Or operator is needed.

If r1.End < r2.Start Or r2.End < r1.Start Then
' Found no overlap between ranges ...
End If

Overlap result

If there is no overlap, we return Nothing and exit the function immediately since we already know the result. Combining the steps, we have:

If r1.End < r2.Start Or r2.End < r1.Start Then
Set IntersectRanges = Nothing
Exit Function
End If

Define a working range

We don’t want to modify either range argument r1 or r2 (see range article for why this matters), so we create a separate range for the work below. We initially assign it to be the first range r1 for simplicity.

Set r = r1.Duplicate

The Duplicate method creates an independent range to modify. Otherwise, the two range variables would literally refer to the same range. We know any possible overlap will include part of r1, so this is a good starting point.

Detecting overlapping range

We’ve already handled the case of no intersection above, so let’s find the overlap between the two ranges.

Left side

The working range r is currently equal to the given range r1. If anything changes, the intersection shrinks the range. Specifically, if the Start of the second range r2 is bigger (later or to the right) in the document than the current Start position, then move the Start position of our working range r.

If r2.Start > r.Start Then
r.Start = r2.Start
End If

Right side

Repeat that idea on the right side. If the End position of r2 is smaller (earlier or to the left) in the document than the current End position, then move the End position of our working range.

If r2.End < r.End Then
r.End = r2.End
End If

Shorter versions

Since both of these commands are super short, we can use a shorthand notation where we don’t require an End If statement. As long as it fits on a single command line, we can instead write the following:

If r2.Start > r.Start Then r.Start = r2.Start
If r2.End < r.End Then r.End = r2.End

This is a matter of preference, but I like to condense them onto one line when the commands are clear.

Return working range result

At this point, the working range r holds our valid overlapping result, so just return it.

Set IntersectRanges = r

No gotchas

The main gotcha of being given an invalid range for r1 or r2 was handled in the foolproof condition at the top of the macro, so I think we’re okay now.

Final Function

Putting everything together, the range intersection function is:

Function IntersectRanges(r1 As Range, r2 As Range) As Range
' Return the intersection of two given ranges
' Returns Nothing if either given range is Nothing
' Returns Nothing if no intersection exists between two valid ranges

' Check for invalid range arguments
If r1 Is Nothing Or r2 Is Nothing Then
Set IntersectRanges = Nothing
Exit Function
End If

' Check for no range overlap (empty set result)
If r1.End < r2.Start Or r2.End < r1.Start Then
Set IntersectRanges = Nothing
Exit Function
End If

' Define working range starting as duplicate of r1
Set r = r1.Duplicate

' Constrain the range based on intersection
' Already checked for empty set above
If r2.Start > r.Start Then r.Start = r2.Start
If r2.End < r.End Then r.End = r2.End

Set IntersectRanges = r
End Function

I mainly used this function to restrict a document range for any action I am a little nervous about. For example, I might restrict a range to be within the screen, so I can visually validate whether the macro, whatever it does, worked correctly.

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.